jackson-src-1.9.2/0000755000175000017500000000000011672662540014423 5ustar jamespagejamespagejackson-src-1.9.2/ant/0000755000175000017500000000000011672662540015205 5ustar jamespagejamespagejackson-src-1.9.2/ant/build-mini.xml0000644000175000017500000000375711655120726017770 0ustar jamespagejamespage jackson-src-1.9.2/ant/build-coverage.xml0000644000175000017500000000730611655120726020621 0ustar jamespagejamespage jackson-src-1.9.2/ant/build-clirr.xml0000644000175000017500000000124511655120726020135 0ustar jamespagejamespage jackson-src-1.9.2/ant/build-test.xml0000644000175000017500000002672411655120726020012 0ustar jamespagejamespage jackson-src-1.9.2/ant/build-jarjar-asm.xml0000644000175000017500000000113111655120726021043 0ustar jamespagejamespage jackson-src-1.9.2/ant/build-maven-deploy.xml0000644000175000017500000002407511655120726021430 0ustar jamespagejamespage jackson-src-1.9.2/ant/build-osgi.xml0000644000175000017500000004403511655120726017767 0ustar jamespagejamespage jackson-src-1.9.2/src/0000755000175000017500000000000011672662540015212 5ustar jamespagejamespagejackson-src-1.9.2/src/smile/0000755000175000017500000000000011655120726016317 5ustar jamespagejamespagejackson-src-1.9.2/src/smile/java/0000755000175000017500000000000011655120726017240 5ustar jamespagejamespagejackson-src-1.9.2/src/smile/java/org/0000755000175000017500000000000011655120726020027 5ustar jamespagejamespagejackson-src-1.9.2/src/smile/java/org/codehaus/0000755000175000017500000000000011655120726021622 5ustar jamespagejamespagejackson-src-1.9.2/src/smile/java/org/codehaus/jackson/0000755000175000017500000000000011655120726023252 5ustar jamespagejamespagejackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/0000755000175000017500000000000011672662540024367 5ustar jamespagejamespagejackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/SmileConstants.java0000644000175000017500000003155711655120726030207 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; /** * Constants used by {@link SmileGenerator} and {@link SmileParser} * * @author tatu */ public final class SmileConstants { /* /********************************************************** /* Thresholds /********************************************************** */ /** * Encoding has special "short" forms for value Strings that can * be represented by 64 bytes of UTF-8 or less. */ public final static int MAX_SHORT_VALUE_STRING_BYTES = 64; /** * Encoding has special "short" forms for field names that can * be represented by 64 bytes of UTF-8 or less. */ public final static int MAX_SHORT_NAME_ASCII_BYTES = 64; /** * Maximum byte length for short non-ASCII names is slightly * less due to having to reserve bytes 0xF8 and above (but * we get one more as values 0 and 1 are not valid) */ public final static int MAX_SHORT_NAME_UNICODE_BYTES = 56; /** * Longest back reference we use for field names is 10 bits; no point * in keeping much more around */ public final static int MAX_SHARED_NAMES = 1024; /** * Longest back reference we use for short shared String values is 10 bits, * so up to (1 << 10) values to keep track of. */ public final static int MAX_SHARED_STRING_VALUES = 1024; /** * Also: whereas we can refer to names of any length, we will only consider * text values that are considered "tiny" or "short" (ones encoded with * length prefix); this value thereby has to be maximum length of Strings * that can be encoded as such. */ public final static int MAX_SHARED_STRING_LENGTH_BYTES = 65; /** * And to make encoding logic tight and simple, we can always * require that output buffer has this amount of space * available before encoding possibly short String (3 bytes since * longest UTF-8 encoded Java char is 3 bytes). * Two extra bytes need to be reserved as well; first for token indicator, * and second for terminating null byte (in case it's not a short String after all) */ public final static int MIN_BUFFER_FOR_POSSIBLE_SHORT_STRING = 1 + (3 * 65); /* /********************************************************** /* Byte markers /********************************************************** */ /** * We need a byte marker to denote end of variable-length Strings. Although * null byte is commonly used, let's try to avoid using it since it can't * be embedded in Web Sockets content (similarly, 0xFF can't). There are * multiple candidates for bytes UTF-8 can not have; 0xFC is chosen to * allow reasonable ordering (highest values meaning most significant * framing function; 0xFF being end-of-content and so on) */ public final static int INT_MARKER_END_OF_STRING = 0xFC; public final static byte BYTE_MARKER_END_OF_STRING = (byte) INT_MARKER_END_OF_STRING; /** * In addition we can use a marker to allow simple framing; splitting * of physical data (like file) into distinct logical sections like * JSON documents. 0xFF makes sense here since it is also used * as end marker for Web Sockets. */ public final static byte BYTE_MARKER_END_OF_CONTENT = (byte) 0xFF; /* /********************************************************** /* Format header: put smile on your data... /********************************************************** */ /** * First byte of data header */ public final static byte HEADER_BYTE_1 = (byte) ':'; /** * Second byte of data header */ public final static byte HEADER_BYTE_2 = (byte) ')'; /** * Third byte of data header */ public final static byte HEADER_BYTE_3 = (byte) '\n'; /** * Current version consists of four zero bits (nibble) */ public final static int HEADER_VERSION_0 = 0x0; /** * Fourth byte of data header; contains version nibble, may * have flags */ public final static byte HEADER_BYTE_4 = (HEADER_VERSION_0 << 4); /** * Indicator bit that indicates whether encoded content may * have Shared names (back references to recently encoded field * names). If no header available, must be * processed as if this was set to true. * If (and only if) header exists, and value is 0, can parser * omit storing of seen names, as it is guaranteed that no back * references exist. */ public final static int HEADER_BIT_HAS_SHARED_NAMES = 0x01; /** * Indicator bit that indicates whether encoded content may * have shared String values (back references to recently encoded * 'short' String values, where short is defined as 64 bytes or less). * If no header available, can be assumed to be 0 (false). * If header exists, and bit value is 1, parsers has to store up * to 1024 most recently seen distinct short String values. */ public final static int HEADER_BIT_HAS_SHARED_STRING_VALUES = 0x02; /** * Indicator bit that indicates whether encoded content may * contain raw (unquoted) binary values. * If no header available, can be assumed to be 0 (false). * If header exists, and bit value is 1, parser can not assume that * specific byte values always have default meaning (specifically, * content end marker 0xFF and header signature can be contained * in binary values) *

* Note that this bit being true does not automatically mean that * such raw binary content indeed exists; just that it may exist. * This because header is written before any binary data may be * written. */ public final static int HEADER_BIT_HAS_RAW_BINARY = 0x04; /* /********************************************************** /* Type prefixes: 3 MSB of token byte /********************************************************** */ // Shared strings are back references for last 63 short (< 64 byte) string values // NOTE: 0x00 is reserved, not used with current version (may be used in future) public final static int TOKEN_PREFIX_SHARED_STRING_SHORT = 0x00; // literals are put between 0x20 and 0x3F to reserve markers (smiley), along with ints/doubles //public final static int TOKEN_PREFIX_MISC_NUMBERS = 0x20; public final static int TOKEN_PREFIX_TINY_ASCII = 0x40; public final static int TOKEN_PREFIX_SMALL_ASCII = 0x60; public final static int TOKEN_PREFIX_TINY_UNICODE = 0x80; public final static int TOKEN_PREFIX_SHORT_UNICODE = 0xA0; // Small ints are 4-bit (-16 to +15) integer constants public final static int TOKEN_PREFIX_SMALL_INT = 0xC0; // And misc types have empty at the end too, to reserve 0xF8 - 0xFF public final static int TOKEN_PREFIX_MISC_OTHER = 0xE0; /* /********************************************************** /* Token literals, normal mode /********************************************************** */ // First, non-structured literals public final static byte TOKEN_LITERAL_EMPTY_STRING = 0x20; public final static byte TOKEN_LITERAL_NULL = 0x21; public final static byte TOKEN_LITERAL_FALSE = 0x22; public final static byte TOKEN_LITERAL_TRUE = 0x23; // And then structured literals public final static byte TOKEN_LITERAL_START_ARRAY = (byte) 0xF8; public final static byte TOKEN_LITERAL_END_ARRAY = (byte) 0xF9; public final static byte TOKEN_LITERAL_START_OBJECT = (byte) 0xFA; public final static byte TOKEN_LITERAL_END_OBJECT = (byte) 0xFB; /* /********************************************************** /* Subtype constants for misc text/binary types /********************************************************** */ /** * Type (for misc, other) used * for regular integral types (byte/short/int/long) */ public final static int TOKEN_MISC_INTEGER = 0x24; /** * Type (for misc, other) used * for regular floating-point types (float, double) */ public final static int TOKEN_MISC_FP = 0x28; /** * Type (for misc, other) used for * variable length UTF-8 encoded text, when it is known to only contain ASCII chars. * Note: 2 LSB are reserved for future use; must be zeroes for now */ public final static int TOKEN_MISC_LONG_TEXT_ASCII = 0xE0; /** * Type (for misc, other) used * for variable length UTF-8 encoded text, when it is NOT known to only contain ASCII chars * (which means it MAY have multi-byte characters) * Note: 2 LSB are reserved for future use; must be zeroes for now */ public final static int TOKEN_MISC_LONG_TEXT_UNICODE = 0xE4; /** * Type (for misc, other) used * for "safe" (encoded by only using 7 LSB, giving 8/7 expansion ratio). * This is usually done to ensure that certain bytes are never included * in encoded data (like 0xFF) * Note: 2 LSB are reserved for future use; must be zeroes for now */ public final static int TOKEN_MISC_BINARY_7BIT = 0xE8; /** * Type (for misc, other) used for shared String values where index * does not fit in "short" reference range (which is 0 - 30). If so, * 2 LSB from here and full following byte are used to get 10-bit * index. Values */ public final static int TOKEN_MISC_SHARED_STRING_LONG = 0xEC; /** * Raw binary data marker is specifically chosen as separate from * other types, since it can have significant impact on framing * (or rather fast scanning based on structure and framing markers). */ public final static int TOKEN_MISC_BINARY_RAW = 0xFD; /* /********************************************************** /* Modifiers for numeric entries /********************************************************** */ /** * Numeric subtype (2 LSB) for {@link #TOKEN_MISC_INTEGER}, * indicating 32-bit integer (int) */ public final static int TOKEN_MISC_INTEGER_32 = 0x00; /** * Numeric subtype (2 LSB) for {@link #TOKEN_MISC_INTEGER}, * indicating 32-bit integer (long) */ public final static int TOKEN_MISC_INTEGER_64 = 0x01; /** * Numeric subtype (2 LSB) for {@link #TOKEN_MISC_INTEGER}, * indicating {@link java.math.BigInteger} type. */ public final static int TOKEN_MISC_INTEGER_BIG = 0x02; // Note: type 3 (0xF3) reserved for future use /** * Numeric subtype (2 LSB) for {@link #TOKEN_MISC_FP}, * indicating 32-bit IEEE single precision floating point number. */ public final static int TOKEN_MISC_FLOAT_32 = 0x00; /** * Numeric subtype (2 LSB) for {@link #TOKEN_MISC_FP}, * indicating 64-bit IEEE double precision floating point number. */ public final static int TOKEN_MISC_FLOAT_64 = 0x01; /** * Numeric subtype (2 LSB) for {@link #TOKEN_MISC_FP}, * indicating {@link java.math.BigDecimal} type. */ public final static int TOKEN_MISC_FLOAT_BIG = 0x02; // Note: type 3 (0xF7) reserved for future use /* /********************************************************** /* Token types for keys /********************************************************** */ /** * Let's use same code for empty key as for empty String value */ public final static byte TOKEN_KEY_EMPTY_STRING = 0x20; public final static int TOKEN_PREFIX_KEY_SHARED_LONG = 0x30; public final static byte TOKEN_KEY_LONG_STRING = 0x34; public final static int TOKEN_PREFIX_KEY_SHARED_SHORT = 0x40; public final static int TOKEN_PREFIX_KEY_ASCII = 0x80; public final static int TOKEN_PREFIX_KEY_UNICODE = 0xC0; /* /********************************************************** /* Basic UTF-8 decode/encode table /********************************************************** */ /** * Additionally we can combine UTF-8 decoding info into similar * data table. * Values indicate "byte length - 1"; meaning -1 is used for * invalid bytes, 0 for single-byte codes, 1 for 2-byte codes * and 2 for 3-byte codes. */ public final static int[] sUtf8UnitLengths; static { int[] table = new int[256]; for (int c = 128; c < 256; ++c) { int code; // We'll add number of bytes needed for decoding if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) code = 1; } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) code = 2; } else if ((c & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all... code = 3; } else { // And -1 seems like a good "universal" error marker... code = -1; } table[c] = code; } sUtf8UnitLengths = table; } } jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/SmileUtil.java0000644000175000017500000000224711655120726027142 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; /** * Class for miscellaneous helper methods. */ public class SmileUtil { public static int zigzagEncode(int input) { // Canonical version: //return (input << 1) ^ (input >> 31); // but this is even better if (input < 0) { return (input << 1) ^ -1; } return (input << 1); } public static int zigzagDecode(int encoded) { // canonical: //return (encoded >>> 1) ^ (-(encoded & 1)); if ((encoded & 1) == 0) { // positive return (encoded >>> 1); } // negative return (encoded >>> 1) ^ -1; } public static long zigzagEncode(long input) { // Canonical version //return (input << 1) ^ (input >> 63); if (input < 0L) { return (input << 1) ^ -1L; } return (input << 1); } public static long zigzagDecode(long encoded) { // canonical: //return (encoded >>> 1) ^ (-(encoded & 1)); if ((encoded & 1) == 0) { // positive return (encoded >>> 1); } // negative return (encoded >>> 1) ^ -1L; } } jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/SmileGenerator.java0000644000175000017500000023752311655120726030162 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; import java.io.*; import java.lang.ref.SoftReference; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import org.codehaus.jackson.*; import org.codehaus.jackson.io.IOContext; import org.codehaus.jackson.io.SerializedString; import org.codehaus.jackson.impl.JsonGeneratorBase; import org.codehaus.jackson.impl.JsonWriteContext; import static org.codehaus.jackson.smile.SmileConstants.*; /** * {@link JsonGenerator} implementation for the experimental "Binary JSON Infoset". * * @author tatu */ public class SmileGenerator extends JsonGeneratorBase { /** * Enumeration that defines all togglable features for Smile generators. */ public enum Feature { /** * Whether to write 4-byte header sequence when starting output or not. * If disabled, no header is written; this may be useful in embedded cases * where context is enough to know that content is encoded using this format. * Note, however, that omitting header means that default settings for * shared names/string values can not be changed. *

* Default setting is true, meaning that header will be written. */ WRITE_HEADER(true), /** * Whether write byte marker that signifies end of logical content segment * ({@link SmileConstants#BYTE_MARKER_END_OF_CONTENT}) when * {@link #close} is called or not. This can be useful when outputting * multiple adjacent logical content segments (documents) into single * physical output unit (file). *

* Default setting is false meaning that such marker is not written. */ WRITE_END_MARKER(false), /** * Whether to use simple 7-bit per byte encoding for binary content when output. * This is necessary ensure that byte 0xFF will never be included in content output. * For other data types this limitation is handled automatically; but since overhead * for binary data (14% size expansion, processing overhead) is non-negligible, * it is not enabled by default. If no binary data is output, feature has no effect. *

* Default setting is true, indicating that binary data is quoted as 7-bit bytes * instead of written raw. */ ENCODE_BINARY_AS_7BIT(true), /** * Whether generator should check if it can "share" field names during generating * content or not. If enabled, can replace repeating field names with back references, * which are more compact and should faster to decode. Downside is that there is some * overhead for writing (need to track existing values, check), as well as decoding. *

* Since field names tend to repeat quite often, this setting is enabled by default. */ CHECK_SHARED_NAMES(true), /** * Whether generator should check if it can "share" short (at most 64 bytes encoded) * String value during generating * content or not. If enabled, can replace repeating Short String values with back references, * which are more compact and should faster to decode. Downside is that there is some * overhead for writing (need to track existing values, check), as well as decoding. *

* Since efficiency of this option depends a lot on type of content being produced, * this option is disabled by default, and should only be enabled if it is likely that * same values repeat relatively often. */ CHECK_SHARED_STRING_VALUES(false) ; protected final boolean _defaultState; protected final int _mask; /** * Method that calculates bit set (flags) of all features that * are enabled by default. */ public static int collectDefaults() { int flags = 0; for (Feature f : values()) { if (f.enabledByDefault()) { flags |= f.getMask(); } } return flags; } private Feature(boolean defaultState) { _defaultState = defaultState; _mask = (1 << ordinal()); } public boolean enabledByDefault() { return _defaultState; } public int getMask() { return _mask; } } /** * Helper class used for keeping track of possibly shareable String * references (for field names and/or short String values) */ protected final static class SharedStringNode { public final String value; public final int index; public SharedStringNode next; public SharedStringNode(String value, int index, SharedStringNode next) { this.value = value; this.index = index; this.next = next; } } /** * To simplify certain operations, we require output buffer length * to allow outputting of contiguous 256 character UTF-8 encoded String * value. Length of the longest UTF-8 code point (from Java char) is 3 bytes, * and we need both initial token byte and single-byte end marker * so we get following value. *

* Note: actually we could live with shorter one; absolute minimum would * be for encoding 64-character Strings. */ private final static int MIN_BUFFER_LENGTH = (3 * 256) + 2; protected final static byte TOKEN_BYTE_LONG_STRING_ASCII = (byte) TOKEN_MISC_LONG_TEXT_ASCII; protected final static byte TOKEN_BYTE_LONG_STRING_UNICODE = (byte) TOKEN_MISC_LONG_TEXT_UNICODE; protected final static byte TOKEN_BYTE_INT_32 = (byte) (TOKEN_MISC_INTEGER | TOKEN_MISC_INTEGER_32); protected final static byte TOKEN_BYTE_INT_64 = (byte) (TOKEN_MISC_INTEGER | TOKEN_MISC_INTEGER_64); protected final static byte TOKEN_BYTE_BIG_INTEGER = (byte) (TOKEN_MISC_INTEGER | TOKEN_MISC_INTEGER_BIG); protected final static byte TOKEN_BYTE_FLOAT_32 = (byte) (TOKEN_MISC_FP | TOKEN_MISC_FLOAT_32); protected final static byte TOKEN_BYTE_FLOAT_64 = (byte) (TOKEN_MISC_FP | TOKEN_MISC_FLOAT_64); protected final static byte TOKEN_BYTE_BIG_DECIMAL = (byte) (TOKEN_MISC_FP | TOKEN_MISC_FLOAT_BIG); protected final static int SURR1_FIRST = 0xD800; protected final static int SURR1_LAST = 0xDBFF; protected final static int SURR2_FIRST = 0xDC00; protected final static int SURR2_LAST = 0xDFFF; protected final static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE; protected final static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE; /* /********************************************************** /* Configuration /********************************************************** */ final protected IOContext _ioContext; final protected OutputStream _out; /** * Bit flag composed of bits that indicate which * {@link org.codehaus.jackson.smile.SmileGenerator.Feature}s * are enabled. */ protected int _smileFeatures; /** * Helper object used for low-level recycling of Smile-generator * specific buffers. * * @since 1.7 */ final protected SmileBufferRecycler _smileBufferRecycler; /* /********************************************************** /* Output buffering /********************************************************** */ /** * Intermediate buffer in which contents are buffered before * being written using {@link #_out}. */ protected byte[] _outputBuffer; /** * Pointer to the next available byte in {@link #_outputBuffer} */ protected int _outputTail = 0; /** * Offset to index after the last valid index in {@link #_outputBuffer}. * Typically same as length of the buffer. */ protected final int _outputEnd; /** * Intermediate buffer in which characters of a String are copied * before being encoded. */ protected char[] _charBuffer; protected final int _charBufferLength; /** * Let's keep track of how many bytes have been output, may prove useful * when debugging. This does not include bytes buffered in * the output buffer, just bytes that have been written using underlying * stream writer. */ protected int _bytesWritten; /* /********************************************************** /* Shared String detection /********************************************************** */ /** * Raw data structure used for checking whether field name to * write can be output using back reference or not. */ protected SharedStringNode[] _seenNames; /** * Number of entries in {@link #_seenNames}; -1 if no shared name * detection is enabled */ protected int _seenNameCount; /** * Raw data structure used for checking whether String value to * write can be output using back reference or not. */ protected SharedStringNode[] _seenStringValues; /** * Number of entries in {@link #_seenStringValues}; -1 if no shared text value * detection is enabled */ protected int _seenStringValueCount; /** * Flag that indicates whether the output buffer is recycable (and * needs to be returned to recycler once we are done) or not. */ protected boolean _bufferRecyclable; /* /********************************************************** /* Thread-local recycling /********************************************************** */ /** * This ThreadLocal contains a {@link java.lang.ref.SoftRerefence} * to a buffer recycler used to provide a low-cost * buffer recycling for Smile-specific buffers. */ final protected static ThreadLocal>> _smileRecyclerRef = new ThreadLocal>>(); /* /********************************************************** /* Life-cycle /********************************************************** */ public SmileGenerator(IOContext ctxt, int jsonFeatures, int smileFeatures, ObjectCodec codec, OutputStream out) { super(jsonFeatures, codec); _smileFeatures = smileFeatures; _ioContext = ctxt; _smileBufferRecycler = _smileBufferRecycler(); _out = out; _bufferRecyclable = true; _outputBuffer = ctxt.allocWriteEncodingBuffer(); _outputEnd = _outputBuffer.length; _charBuffer = ctxt.allocConcatBuffer(); _charBufferLength = _charBuffer.length; // let's just sanity check to prevent nasty odd errors if (_outputEnd < MIN_BUFFER_LENGTH) { throw new IllegalStateException("Internal encoding buffer length ("+_outputEnd +") too short, must be at least "+MIN_BUFFER_LENGTH); } if ((smileFeatures & Feature.CHECK_SHARED_NAMES.getMask()) == 0) { _seenNames = null; _seenNameCount = -1; } else { _seenNames = _smileBufferRecycler.allocSeenNamesBuffer(); if (_seenNames == null) { _seenNames = new SharedStringNode[SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH]; } _seenNameCount = 0; } if ((smileFeatures & Feature.CHECK_SHARED_STRING_VALUES.getMask()) == 0) { _seenStringValues = null; _seenStringValueCount = -1; } else { _seenStringValues = _smileBufferRecycler.allocSeenStringValuesBuffer(); if (_seenStringValues == null) { _seenStringValues = new SharedStringNode[SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH]; } _seenStringValueCount = 0; } } public SmileGenerator(IOContext ctxt, int jsonFeatures, int smileFeatures, ObjectCodec codec, OutputStream out, byte[] outputBuffer, int offset, boolean bufferRecyclable) { super(jsonFeatures, codec); _smileFeatures = smileFeatures; _ioContext = ctxt; _smileBufferRecycler = _smileBufferRecycler(); _out = out; _bufferRecyclable = bufferRecyclable; _outputTail = offset; _outputBuffer = outputBuffer; _outputEnd = _outputBuffer.length; _charBuffer = ctxt.allocConcatBuffer(); _charBufferLength = _charBuffer.length; // let's just sanity check to prevent nasty odd errors if (_outputEnd < MIN_BUFFER_LENGTH) { throw new IllegalStateException("Internal encoding buffer length ("+_outputEnd +") too short, must be at least "+MIN_BUFFER_LENGTH); } if ((smileFeatures & Feature.CHECK_SHARED_NAMES.getMask()) == 0) { _seenNames = null; _seenNameCount = -1; } else { _seenNames = _smileBufferRecycler.allocSeenNamesBuffer(); if (_seenNames == null) { _seenNames = new SharedStringNode[SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH]; } _seenNameCount = 0; } if ((smileFeatures & Feature.CHECK_SHARED_STRING_VALUES.getMask()) == 0) { _seenStringValues = null; _seenStringValueCount = -1; } else { _seenStringValues = _smileBufferRecycler.allocSeenStringValuesBuffer(); if (_seenStringValues == null) { _seenStringValues = new SharedStringNode[SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH]; } _seenStringValueCount = 0; } } /** * Method that can be called to explicitly write Smile document header. * Note that usually you do not need to call this for first document to output, * but rather only if you intend to write multiple root-level documents * with same generator (and even in that case this is optional thing to do). * As a result usually only {@link SmileFactory} calls this method. */ public void writeHeader() throws IOException { int last = HEADER_BYTE_4; if ((_smileFeatures & Feature.CHECK_SHARED_NAMES.getMask()) != 0) { last |= SmileConstants.HEADER_BIT_HAS_SHARED_NAMES; } if ((_smileFeatures & Feature.CHECK_SHARED_STRING_VALUES.getMask()) != 0) { last |= SmileConstants.HEADER_BIT_HAS_SHARED_STRING_VALUES; } if ((_smileFeatures & Feature.ENCODE_BINARY_AS_7BIT.getMask()) == 0) { last |= SmileConstants.HEADER_BIT_HAS_RAW_BINARY; } _writeBytes(HEADER_BYTE_1, HEADER_BYTE_2, HEADER_BYTE_3, (byte) last); } protected final static SmileBufferRecycler _smileBufferRecycler() { SoftReference> ref = _smileRecyclerRef.get(); SmileBufferRecycler br = (ref == null) ? null : ref.get(); if (br == null) { br = new SmileBufferRecycler(); _smileRecyclerRef.set(new SoftReference>(br)); } return br; } /* /********************************************************** /* Overridden methods, configuration /********************************************************** */ /** * No way (or need) to indent anything, so let's block any attempts. * (should we throw an exception instead?) */ @Override public JsonGenerator useDefaultPrettyPrinter() { return this; } /** * No way (or need) to indent anything, so let's block any attempts. * (should we throw an exception instead?) */ @Override public JsonGenerator setPrettyPrinter(PrettyPrinter pp) { return this; } @Override public Object getOutputTarget() { return _out; } /* /********************************************************** /* Overridden methods, write methods /********************************************************** */ /* And then methods overridden to make final, streamline some * aspects... */ @Override public final void writeFieldName(String name) throws IOException, JsonGenerationException { if (_writeContext.writeFieldName(name) == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name); } @Override public final void writeFieldName(SerializedString name) throws IOException, JsonGenerationException { // Object is a value, need to verify it's allowed if (_writeContext.writeFieldName(name.getValue()) == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name); } @Override public final void writeFieldName(SerializableString name) throws IOException, JsonGenerationException { // Object is a value, need to verify it's allowed if (_writeContext.writeFieldName(name.getValue()) == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name); } @Override public final void writeStringField(String fieldName, String value) throws IOException, JsonGenerationException { if (_writeContext.writeFieldName(fieldName) == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(fieldName); writeString(value); } /* /********************************************************** /* Extended API, configuration /********************************************************** */ public SmileGenerator enable(Feature f) { _smileFeatures |= f.getMask(); return this; } public SmileGenerator disable(Feature f) { _smileFeatures &= ~f.getMask(); return this; } public final boolean isEnabled(Feature f) { return (_smileFeatures & f.getMask()) != 0; } public SmileGenerator configure(Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; } /* /********************************************************** /* Extended API, other /********************************************************** */ /** * Method for directly inserting specified byte in output at * current position. *

* NOTE: only use this method if you really know what you are doing. */ public void writeRaw(byte b) throws IOException, JsonGenerationException { _writeByte(TOKEN_LITERAL_START_ARRAY); } /** * Method for directly inserting specified bytes in output at * current position. *

* NOTE: only use this method if you really know what you are doing. */ public void writeBytes(byte[] data, int offset, int len) throws IOException { _writeBytes(data, offset, len); } /* /********************************************************** /* Output method implementations, structural /********************************************************** */ @Override public final void writeStartArray() throws IOException, JsonGenerationException { _verifyValueWrite("start an array"); _writeContext = _writeContext.createChildArrayContext(); _writeByte(TOKEN_LITERAL_START_ARRAY); } @Override public final void writeEndArray() throws IOException, JsonGenerationException { if (!_writeContext.inArray()) { _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc()); } _writeByte(TOKEN_LITERAL_END_ARRAY); _writeContext = _writeContext.getParent(); } @Override public final void writeStartObject() throws IOException, JsonGenerationException { _verifyValueWrite("start an object"); _writeContext = _writeContext.createChildObjectContext(); _writeByte(TOKEN_LITERAL_START_OBJECT); } @Override public final void writeEndObject() throws IOException, JsonGenerationException { if (!_writeContext.inObject()) { _reportError("Current context not an object but "+_writeContext.getTypeDesc()); } _writeContext = _writeContext.getParent(); _writeByte(TOKEN_LITERAL_END_OBJECT); } private final void _writeFieldName(String name) throws IOException, JsonGenerationException { int len = name.length(); if (len == 0) { _writeByte(TOKEN_KEY_EMPTY_STRING); return; } // First: is it something we can share? if (_seenNameCount >= 0) { int ix = _findSeenName(name); if (ix >= 0) { _writeSharedNameReference(ix); return; } } if (len > MAX_SHORT_NAME_UNICODE_BYTES) { // can not be a 'short' String; off-line (rare case) _writeNonShortFieldName(name, len); return; } // first: ensure we have enough space if ((_outputTail + MIN_BUFFER_FOR_POSSIBLE_SHORT_STRING) >= _outputEnd) { _flushBuffer(); } // then let's copy String chars to char buffer, faster than using getChar (measured, profiled) name.getChars(0, len, _charBuffer, 0); int origOffset = _outputTail; ++_outputTail; // to reserve space for type token int byteLen = _shortUTF8Encode(_charBuffer, 0, len); byte typeToken; // ASCII? if (byteLen == len) { if (byteLen <= MAX_SHORT_NAME_ASCII_BYTES) { // yes, is short indeed typeToken = (byte) ((TOKEN_PREFIX_KEY_ASCII - 1) + byteLen); } else { // longer albeit ASCII typeToken = TOKEN_KEY_LONG_STRING; // and we will need String end marker byte _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } } else { // not all ASCII if (byteLen <= MAX_SHORT_NAME_UNICODE_BYTES) { // yes, is short indeed // note: since 2 is smaller allowed length, offset differs from one used for typeToken = (byte) ((TOKEN_PREFIX_KEY_UNICODE - 2) + byteLen); } else { // nope, longer non-ASCII Strings typeToken = TOKEN_KEY_LONG_STRING; // and we will need String end marker byte _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } } // and then sneak in type token now that know the details _outputBuffer[origOffset] = typeToken; // Also, keep track if we can use back-references (shared names) if (_seenNameCount >= 0) { _addSeenName(name); } } private final void _writeNonShortFieldName(final String name, final int len) throws IOException, JsonGenerationException { _writeByte(TOKEN_KEY_LONG_STRING); // can we still make a temp copy? if (len > _charBufferLength) { // nah, not even that _slowUTF8Encode(name); } else { // yep. name.getChars(0, len, _charBuffer, 0); // but will encoded version fit in buffer? int maxLen = len + len + len; if (maxLen <= _outputBuffer.length) { // yes indeed if ((_outputTail + maxLen) >= _outputEnd) { _flushBuffer(); } _shortUTF8Encode(_charBuffer, 0, len); } else { // nope, need bit slower variant _mediumUTF8Encode(_charBuffer, 0, len); } } if (_seenNameCount >= 0) { _addSeenName(name); } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } protected final void _writeFieldName(SerializableString name) throws IOException, JsonGenerationException { final int charLen = name.charLength(); if (charLen == 0) { _writeByte(TOKEN_KEY_EMPTY_STRING); return; } final byte[] bytes = name.asUnquotedUTF8(); final int byteLen = bytes.length; if (byteLen != charLen) { _writeFieldNameUnicode(name, bytes); return; } // Then: is it something we can share? if (_seenNameCount >= 0) { int ix = _findSeenName(name.getValue()); if (ix >= 0) { _writeSharedNameReference(ix); return; } } // Common case: short ASCII name that fits in buffer as is if (byteLen <= MAX_SHORT_NAME_ASCII_BYTES) { // output buffer is bigger than what we need, always, so if ((_outputTail + byteLen) >= _outputEnd) { // need marker byte and actual bytes _flushBuffer(); } _outputBuffer[_outputTail++] = (byte) ((TOKEN_PREFIX_KEY_ASCII - 1) + byteLen); System.arraycopy(bytes, 0, _outputBuffer, _outputTail, byteLen); _outputTail += byteLen; } else { _writeLongAsciiFieldName(bytes); } // Also, keep track if we can use back-references (shared names) if (_seenNameCount >= 0) { _addSeenName(name.getValue()); } } private final void _writeLongAsciiFieldName(byte[] bytes) throws IOException, JsonGenerationException { final int byteLen = bytes.length; if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = TOKEN_KEY_LONG_STRING; // Ok. Enough room? if ((_outputTail + byteLen + 1) < _outputEnd) { System.arraycopy(bytes, 0, _outputBuffer, _outputTail, byteLen); _outputTail += byteLen; } else { _flushBuffer(); // either way, do intermediate copy if name is relatively short // Need to copy? if (byteLen < MIN_BUFFER_LENGTH) { System.arraycopy(bytes, 0, _outputBuffer, _outputTail, byteLen); _outputTail += byteLen; } else { // otherwise, just write as is if (_outputTail > 0) { _flushBuffer(); } _out.write(bytes, 0, byteLen); } } _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } protected final void _writeFieldNameUnicode(SerializableString name, byte[] bytes) throws IOException, JsonGenerationException { // Then: is it something we can share? if (_seenNameCount >= 0) { int ix = _findSeenName(name.getValue()); if (ix >= 0) { _writeSharedNameReference(ix); return; } } final int byteLen = bytes.length; // Common case: short Unicode name that fits in output buffer if (byteLen <= MAX_SHORT_NAME_UNICODE_BYTES) { if ((_outputTail + byteLen) >= _outputEnd) { // need marker byte and actual bytes _flushBuffer(); } // note: since 2 is smaller allowed length, offset differs from one used for _outputBuffer[_outputTail++] = (byte) ((TOKEN_PREFIX_KEY_UNICODE - 2) + byteLen); System.arraycopy(bytes, 0, _outputBuffer, _outputTail, byteLen); _outputTail += byteLen; // Also, keep track if we can use back-references (shared names) if (_seenNameCount >= 0) { _addSeenName(name.getValue()); } return; } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = TOKEN_KEY_LONG_STRING; // Ok. Enough room? if ((_outputTail + byteLen + 1) < _outputEnd) { System.arraycopy(bytes, 0, _outputBuffer, _outputTail, byteLen); _outputTail += byteLen; } else { _flushBuffer(); // either way, do intermediate copy if name is relatively short // Need to copy? if (byteLen < MIN_BUFFER_LENGTH) { System.arraycopy(bytes, 0, _outputBuffer, _outputTail, byteLen); _outputTail += byteLen; } else { // otherwise, just write as is if (_outputTail > 0) { _flushBuffer(); } _out.write(bytes, 0, byteLen); } } _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; // Also, keep track if we can use back-references (shared names) if (_seenNameCount >= 0) { _addSeenName(name.getValue()); } } private final void _writeSharedNameReference(int ix) throws IOException,JsonGenerationException { // 03-Mar-2011, tatu: Related to [JACKSON-525], let's add a sanity check here if (ix >= _seenNameCount) { throw new IllegalArgumentException("Internal error: trying to write shared name with index "+ix +"; but have only seen "+_seenNameCount+" so far!"); } if (ix < 64) { _writeByte((byte) (TOKEN_PREFIX_KEY_SHARED_SHORT + ix)); } else { _writeBytes(((byte) (TOKEN_PREFIX_KEY_SHARED_LONG + (ix >> 8))), (byte) ix); } } /* /********************************************************** /* Output method implementations, textual /********************************************************** */ @Override public void writeString(String text) throws IOException,JsonGenerationException { if (text == null) { writeNull(); return; } _verifyValueWrite("write String value"); int len = text.length(); if (len == 0) { _writeByte(TOKEN_LITERAL_EMPTY_STRING); return; } // Longer string handling off-lined if (len > MAX_SHARED_STRING_LENGTH_BYTES) { _writeNonSharedString(text, len); return; } // Then: is it something we can share? if (_seenStringValueCount >= 0) { int ix = _findSeenStringValue(text); if (ix >= 0) { _writeSharedStringValueReference(ix); return; } } // possibly short string (but not necessarily) // first: ensure we have enough space if ((_outputTail + MIN_BUFFER_FOR_POSSIBLE_SHORT_STRING) >= _outputEnd) { _flushBuffer(); } // then let's copy String chars to char buffer, faster than using getChar (measured, profiled) text.getChars(0, len, _charBuffer, 0); int origOffset = _outputTail; ++_outputTail; // to leave room for type token int byteLen = _shortUTF8Encode(_charBuffer, 0, len); if (byteLen <= MAX_SHORT_VALUE_STRING_BYTES) { // yes, is short indeed // plus keep reference, if it could be shared: if (_seenStringValueCount >= 0) { _addSeenStringValue(text); } if (byteLen == len) { // and all ASCII _outputBuffer[origOffset] = (byte) ((TOKEN_PREFIX_TINY_ASCII - 1) + byteLen); } else { // not just ASCII // note: since length 1 can not be used here, value range is offset by 2, not 1 _outputBuffer[origOffset] = (byte) ((TOKEN_PREFIX_TINY_UNICODE - 2) + byteLen); } } else { // nope, longer String _outputBuffer[origOffset] = (byteLen == len) ? TOKEN_BYTE_LONG_STRING_ASCII : TOKEN_BYTE_LONG_STRING_UNICODE; // and we will need String end marker byte _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } } private final void _writeSharedStringValueReference(int ix) throws IOException,JsonGenerationException { // 03-Mar-2011, tatu: Related to [JACKSON-525], let's add a sanity check here if (ix >= _seenStringValueCount) { throw new IllegalArgumentException("Internal error: trying to write shared String value with index "+ix +"; but have only seen "+_seenStringValueCount+" so far!"); } if (ix < 31) { // add 1, as byte 0 is omitted _writeByte((byte) (TOKEN_PREFIX_SHARED_STRING_SHORT + 1 + ix)); } else { _writeBytes(((byte) (TOKEN_MISC_SHARED_STRING_LONG + (ix >> 8))), (byte) ix); } } /** * Helper method called to handle cases where String value to write is known * to be long enough not to be shareable. */ private final void _writeNonSharedString(final String text, final int len) throws IOException,JsonGenerationException { // First: can we at least make a copy to char[]? if (len > _charBufferLength) { // nope; need to skip copy step (alas; this is slower) _writeByte(TOKEN_BYTE_LONG_STRING_UNICODE); _slowUTF8Encode(text); _writeByte(BYTE_MARKER_END_OF_STRING); return; } text.getChars(0, len, _charBuffer, 0); // Expansion can be 3x for Unicode; and then there's type byte and end marker, so: int maxLen = len + len + len + 2; // Next: does it always fit within output buffer? if (maxLen > _outputBuffer.length) { // nope // can't rewrite type buffer, so can't speculate it might be all-ASCII _writeByte(TOKEN_BYTE_LONG_STRING_UNICODE); _mediumUTF8Encode(_charBuffer, 0, len); _writeByte(BYTE_MARKER_END_OF_STRING); return; } if ((_outputTail + maxLen) >= _outputEnd) { _flushBuffer(); } int origOffset = _outputTail; // can't say for sure if it's ASCII or Unicode, so: _writeByte(TOKEN_BYTE_LONG_STRING_ASCII); int byteLen = _shortUTF8Encode(_charBuffer, 0, len); // If not ASCII, fix type: if (byteLen > len) { _outputBuffer[origOffset] = TOKEN_BYTE_LONG_STRING_UNICODE; } _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } @Override public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { // Shared strings are tricky; easiest to just construct String, call the other method if (len <= MAX_SHARED_STRING_LENGTH_BYTES && _seenStringValueCount >= 0 && len > 0) { writeString(new String(text, offset, len)); return; } _verifyValueWrite("write String value"); if (len == 0) { _writeByte(TOKEN_LITERAL_EMPTY_STRING); return; } if (len <= MAX_SHORT_VALUE_STRING_BYTES) { // possibly short strings (not necessarily) // first: ensure we have enough space if ((_outputTail + MIN_BUFFER_FOR_POSSIBLE_SHORT_STRING) >= _outputEnd) { _flushBuffer(); } int origOffset = _outputTail; ++_outputTail; // to leave room for type token int byteLen = _shortUTF8Encode(text, offset, offset+len); byte typeToken; if (byteLen <= MAX_SHORT_VALUE_STRING_BYTES) { // yes, is short indeed if (byteLen == len) { // and all ASCII typeToken = (byte) ((TOKEN_PREFIX_TINY_ASCII - 1) + byteLen); } else { // not just ASCII typeToken = (byte) ((TOKEN_PREFIX_TINY_UNICODE - 2) + byteLen); } } else { // nope, longer non-ASCII Strings typeToken = TOKEN_BYTE_LONG_STRING_UNICODE; // and we will need String end marker byte _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } // and then sneak in type token now that know the details _outputBuffer[origOffset] = typeToken; } else { // "long" String, never shared // but might still fit within buffer? int maxLen = len + len + len + 2; if (maxLen <= _outputBuffer.length) { // yes indeed if ((_outputTail + maxLen) >= _outputEnd) { _flushBuffer(); } int origOffset = _outputTail; _writeByte(TOKEN_BYTE_LONG_STRING_UNICODE); int byteLen = _shortUTF8Encode(text, offset, offset+len); // if it's ASCII, let's revise our type determination (to help decoder optimize) if (byteLen == len) { _outputBuffer[origOffset] = TOKEN_BYTE_LONG_STRING_ASCII; } _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } else { _writeByte(TOKEN_BYTE_LONG_STRING_UNICODE); _mediumUTF8Encode(text, offset, offset+len); _writeByte(BYTE_MARKER_END_OF_STRING); } } } @Override public final void writeString(SerializableString sstr) throws IOException, JsonGenerationException { _verifyValueWrite("write String value"); // First: is it empty? String str = sstr.getValue(); int len = str.length(); if (len == 0) { _writeByte(TOKEN_LITERAL_EMPTY_STRING); return; } // Second: something we can share? if (len <= MAX_SHARED_STRING_LENGTH_BYTES && _seenStringValueCount >= 0) { int ix = _findSeenStringValue(str); if (ix >= 0) { _writeSharedStringValueReference(ix); return; } } // If not, use pre-encoded version byte[] raw = sstr.asUnquotedUTF8(); final int byteLen = raw.length; if (byteLen <= MAX_SHORT_VALUE_STRING_BYTES) { // short string // first: ensure we have enough space if ((_outputTail + byteLen + 1) >= _outputEnd) { _flushBuffer(); } // ASCII or Unicode? int typeToken = (byteLen == len) ? ((TOKEN_PREFIX_TINY_ASCII - 1) + byteLen) : ((TOKEN_PREFIX_TINY_UNICODE - 2) + byteLen) ; _outputBuffer[_outputTail++] = (byte) typeToken; System.arraycopy(raw, 0, _outputBuffer, _outputTail, byteLen); _outputTail += byteLen; // plus keep reference, if it could be shared: if (_seenStringValueCount >= 0) { _addSeenStringValue(sstr.getValue()); } } else { // "long" String, never shared // but might still fit within buffer? byte typeToken = (byteLen == len) ? TOKEN_BYTE_LONG_STRING_ASCII : TOKEN_BYTE_LONG_STRING_UNICODE; _writeByte(typeToken); _writeBytes(raw, 0, raw.length); _writeByte(BYTE_MARKER_END_OF_STRING); } } @Override public void writeRawUTF8String(byte[] text, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write String value"); // first: is it empty String? if (len == 0) { _writeByte(TOKEN_LITERAL_EMPTY_STRING); return; } // Sanity check: shared-strings incompatible with raw String writing if (_seenStringValueCount >= 0) { throw new UnsupportedOperationException("Can not use direct UTF-8 write methods when 'Feature.CHECK_SHARED_STRING_VALUES' enabled"); } /* Other practical limitation is that we do not really know if it might be * ASCII or not; and figuring it out is rather slow. So, best we can do is * to declare we do not know it is ASCII (i.e. "is Unicode"). */ if (len <= MAX_SHARED_STRING_LENGTH_BYTES) { // up to 65 Unicode bytes // first: ensure we have enough space if ((_outputTail + len) >= _outputEnd) { // bytes, plus one for type indicator _flushBuffer(); } /* 11-Feb-2011, tatu: As per [JACKSON-492], mininum length for "Unicode" * String is 2; 1 byte length must be ASCII. */ if (len == 1) { _outputBuffer[_outputTail++] = TOKEN_PREFIX_TINY_ASCII; // length of 1 cancels out (len-1) _outputBuffer[_outputTail++] = text[offset]; } else { _outputBuffer[_outputTail++] = (byte) ((TOKEN_PREFIX_TINY_UNICODE - 2) + len); System.arraycopy(text, offset, _outputBuffer, _outputTail, len); _outputTail += len; } } else { // "long" String // but might still fit within buffer? int maxLen = len + len + len + 2; if (maxLen <= _outputBuffer.length) { // yes indeed if ((_outputTail + maxLen) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = TOKEN_BYTE_LONG_STRING_UNICODE; System.arraycopy(text, offset, _outputBuffer, _outputTail, len); _outputTail += len; _outputBuffer[_outputTail++] = BYTE_MARKER_END_OF_STRING; } else { _writeByte(TOKEN_BYTE_LONG_STRING_UNICODE); _writeBytes(text, offset, len); _writeByte(BYTE_MARKER_END_OF_STRING); } } } @Override public final void writeUTF8String(byte[] text, int offset, int len) throws IOException, JsonGenerationException { // Since no escaping is needed, same as 'writeRawUTF8String' writeRawUTF8String(text, offset, len); } /* /********************************************************** /* Output method implementations, unprocessed ("raw") /********************************************************** */ @Override public void writeRaw(String text) throws IOException, JsonGenerationException { throw _notSupported(); } @Override public void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException { throw _notSupported(); } @Override public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException { throw _notSupported(); } @Override public void writeRaw(char c) throws IOException, JsonGenerationException { throw _notSupported(); } @Override public void writeRawValue(String text) throws IOException, JsonGenerationException { throw _notSupported(); } @Override public void writeRawValue(String text, int offset, int len) throws IOException, JsonGenerationException { throw _notSupported(); } @Override public void writeRawValue(char[] text, int offset, int len) throws IOException, JsonGenerationException { throw _notSupported(); } /* /********************************************************** /* Output method implementations, base64-encoded binary /********************************************************** */ @Override public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException, JsonGenerationException { if (data == null) { writeNull(); return; } _verifyValueWrite("write Binary value"); if (this.isEnabled(Feature.ENCODE_BINARY_AS_7BIT)) { _writeByte((byte) TOKEN_MISC_BINARY_7BIT); _write7BitBinaryWithLength(data, offset, len); } else { _writeByte((byte) TOKEN_MISC_BINARY_RAW ); _writePositiveVInt(len); // raw is dead simple of course: _writeBytes(data, offset, len); } } /* /********************************************************** /* Output method implementations, primitive /********************************************************** */ @Override public void writeBoolean(boolean state) throws IOException, JsonGenerationException { _verifyValueWrite("write boolean value"); if (state) { _writeByte(TOKEN_LITERAL_TRUE); } else { _writeByte(TOKEN_LITERAL_FALSE); } } @Override public void writeNull() throws IOException, JsonGenerationException { _verifyValueWrite("write null value"); _writeByte(TOKEN_LITERAL_NULL); } @Override public void writeNumber(int i) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); // First things first: let's zigzag encode number i = SmileUtil.zigzagEncode(i); // tiny (single byte) or small (type + 6-bit value) number? if (i <= 0x3F && i >= 0) { if (i <= 0x1F) { // tiny _writeByte((byte) (TOKEN_PREFIX_SMALL_INT + i)); return; } // nope, just small, 2 bytes (type, 1-byte zigzag value) for 6 bit value _writeBytes(TOKEN_BYTE_INT_32, (byte) (0x80 + i)); return; } // Ok: let's find minimal representation then byte b0 = (byte) (0x80 + (i & 0x3F)); i >>>= 6; if (i <= 0x7F) { // 13 bits is enough (== 3 byte total encoding) _writeBytes(TOKEN_BYTE_INT_32, (byte) i, b0); return; } byte b1 = (byte) (i & 0x7F); i >>= 7; if (i <= 0x7F) { _writeBytes(TOKEN_BYTE_INT_32, (byte) i, b1, b0); return; } byte b2 = (byte) (i & 0x7F); i >>= 7; if (i <= 0x7F) { _writeBytes(TOKEN_BYTE_INT_32, (byte) i, b2, b1, b0); return; } // no, need all 5 bytes byte b3 = (byte) (i & 0x7F); _writeBytes(TOKEN_BYTE_INT_32, (byte) (i >> 7), b3, b2, b1, b0); } @Override public void writeNumber(long l) throws IOException, JsonGenerationException { // First: maybe 32 bits is enough? if (l <= MAX_INT_AS_LONG && l >= MIN_INT_AS_LONG) { writeNumber((int) l); return; } _verifyValueWrite("write number"); // Then let's zigzag encode it l = SmileUtil.zigzagEncode(l); // Ok, well, we do know that 5 lowest-significant bytes are needed int i = (int) l; // 4 can be extracted from lower int byte b0 = (byte) (0x80 + (i & 0x3F)); // sign bit set in the last byte byte b1 = (byte) ((i >> 6) & 0x7F); byte b2 = (byte) ((i >> 13) & 0x7F); byte b3 = (byte) ((i >> 20) & 0x7F); // fifth one is split between ints: l >>>= 27; byte b4 = (byte) (((int) l) & 0x7F); // which may be enough? i = (int) (l >> 7); if (i == 0) { _writeBytes(TOKEN_BYTE_INT_64, b4, b3, b2, b1, b0); return; } if (i <= 0x7F) { _writeBytes(TOKEN_BYTE_INT_64, (byte) i); _writeBytes(b4, b3, b2, b1, b0); return; } byte b5 = (byte) (i & 0x7F); i >>= 7; if (i <= 0x7F) { _writeBytes(TOKEN_BYTE_INT_64, (byte) i); _writeBytes(b5, b4, b3, b2, b1, b0); return; } byte b6 = (byte) (i & 0x7F); i >>= 7; if (i <= 0x7F) { _writeBytes(TOKEN_BYTE_INT_64, (byte) i, b6); _writeBytes(b5, b4, b3, b2, b1, b0); return; } byte b7 = (byte) (i & 0x7F); i >>= 7; if (i <= 0x7F) { _writeBytes(TOKEN_BYTE_INT_64, (byte) i, b7, b6); _writeBytes(b5, b4, b3, b2, b1, b0); return; } byte b8 = (byte) (i & 0x7F); i >>= 7; // must be done, with 10 bytes! (9 * 7 + 6 == 69 bits; only need 63) _writeBytes(TOKEN_BYTE_INT_64, (byte) i, b8, b7, b6); _writeBytes(b5, b4, b3, b2, b1, b0); } @Override public void writeNumber(BigInteger v) throws IOException, JsonGenerationException { if (v == null) { writeNull(); return; } _verifyValueWrite("write number"); // quite simple: type, and then VInt-len prefixed 7-bit encoded binary data: _writeByte(TOKEN_BYTE_BIG_INTEGER); byte[] data = v.toByteArray(); _write7BitBinaryWithLength(data, 0, data.length); } @Override public void writeNumber(double d) throws IOException, JsonGenerationException { // Ok, now, we needed token type byte plus 10 data bytes (7 bits each) _ensureRoomForOutput(11); _verifyValueWrite("write number"); /* 17-Apr-2010, tatu: could also use 'doubleToIntBits', but it seems more accurate to use * exact representation; and possibly faster. However, if there are cases * where collapsing of NaN was needed (for non-Java clients), this can * be changed */ long l = Double.doubleToRawLongBits(d); _outputBuffer[_outputTail++] = TOKEN_BYTE_FLOAT_64; // Handle first 29 bits (single bit first, then 4 x 7 bits) int hi5 = (int) (l >>> 35); _outputBuffer[_outputTail+4] = (byte) (hi5 & 0x7F); hi5 >>= 7; _outputBuffer[_outputTail+3] = (byte) (hi5 & 0x7F); hi5 >>= 7; _outputBuffer[_outputTail+2] = (byte) (hi5 & 0x7F); hi5 >>= 7; _outputBuffer[_outputTail+1] = (byte) (hi5 & 0x7F); hi5 >>= 7; _outputBuffer[_outputTail] = (byte) hi5; _outputTail += 5; // Then split byte (one that crosses lo/hi int boundary), 7 bits { int mid = (int) (l >> 28); _outputBuffer[_outputTail++] = (byte) (mid & 0x7F); } // and then last 4 bytes (28 bits) int lo4 = (int) l; _outputBuffer[_outputTail+3] = (byte) (lo4 & 0x7F); lo4 >>= 7; _outputBuffer[_outputTail+2] = (byte) (lo4 & 0x7F); lo4 >>= 7; _outputBuffer[_outputTail+1] = (byte) (lo4 & 0x7F); lo4 >>= 7; _outputBuffer[_outputTail] = (byte) (lo4 & 0x7F); _outputTail += 4; } @Override public void writeNumber(float f) throws IOException, JsonGenerationException { // Ok, now, we needed token type byte plus 5 data bytes (7 bits each) _ensureRoomForOutput(6); _verifyValueWrite("write number"); /* 17-Apr-2010, tatu: could also use 'floatToIntBits', but it seems more accurate to use * exact representation; and possibly faster. However, if there are cases * where collapsing of NaN was needed (for non-Java clients), this can * be changed */ int i = Float.floatToRawIntBits(f); _outputBuffer[_outputTail++] = TOKEN_BYTE_FLOAT_32; _outputBuffer[_outputTail+4] = (byte) (i & 0x7F); i >>= 7; _outputBuffer[_outputTail+3] = (byte) (i & 0x7F); i >>= 7; _outputBuffer[_outputTail+2] = (byte) (i & 0x7F); i >>= 7; _outputBuffer[_outputTail+1] = (byte) (i & 0x7F); i >>= 7; _outputBuffer[_outputTail] = (byte) (i & 0x7F); _outputTail += 5; } @Override public void writeNumber(BigDecimal dec) throws IOException, JsonGenerationException { if (dec == null) { writeNull(); return; } _verifyValueWrite("write number"); _writeByte(TOKEN_BYTE_BIG_DECIMAL); int scale = dec.scale(); // Ok, first output scale as VInt _writeSignedVInt(scale); BigInteger unscaled = dec.unscaledValue(); byte[] data = unscaled.toByteArray(); // And then binary data in "safe" mode (7-bit values) _write7BitBinaryWithLength(data, 0, data.length); } @Override public void writeNumber(String encodedValue) throws IOException,JsonGenerationException, UnsupportedOperationException { /* 17-Apr-2010, tatu: Could try parsing etc; but for now let's not bother, it could * just be some non-standard representation that caller wants to pass */ throw _notSupported(); } /* /********************************************************** /* Implementations for other methods /********************************************************** */ @Override protected final void _verifyValueWrite(String typeMsg) throws IOException, JsonGenerationException { int status = _writeContext.writeValue(); if (status == JsonWriteContext.STATUS_EXPECT_NAME) { _reportError("Can not "+typeMsg+", expecting field name"); } } /* /********************************************************** /* Low-level output handling /********************************************************** */ @Override public final void flush() throws IOException { _flushBuffer(); if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) { _out.flush(); } } @Override public void close() throws IOException { /* 05-Dec-2008, tatu: To add [JACKSON-27], need to close open * scopes. */ // First: let's see that we still have buffers... if (_outputBuffer != null && isEnabled(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT)) { while (true) { JsonStreamContext ctxt = getOutputContext(); if (ctxt.inArray()) { writeEndArray(); } else if (ctxt.inObject()) { writeEndObject(); } else { break; } } } boolean wasClosed = _closed; super.close(); if (!wasClosed && isEnabled(Feature.WRITE_END_MARKER)) { _writeByte(BYTE_MARKER_END_OF_CONTENT); } _flushBuffer(); if (_ioContext.isResourceManaged() || isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET)) { _out.close(); } else { // If we can't close it, we should at least flush _out.flush(); } // Internal buffer(s) generator has can now be released as well _releaseBuffers(); } /* /********************************************************** /* Internal methods, UTF-8 encoding /********************************************************** */ /** * Helper method called when the whole character sequence is known to * fit in the output buffer regardless of UTF-8 expansion. */ private final int _shortUTF8Encode(char[] str, int i, int end) { // First: let's see if it's all ASCII: that's rather fast int ptr = _outputTail; final byte[] outBuf = _outputBuffer; do { int c = str[i]; if (c > 0x7F) { return _shortUTF8Encode2(str, i, end, ptr); } outBuf[ptr++] = (byte) c; } while (++i < end); int codedLen = ptr - _outputTail; _outputTail = ptr; return codedLen; } /** * Helper method called when the whole character sequence is known to * fit in the output buffer, but not all characters are single-byte (ASCII) * characters. */ private final int _shortUTF8Encode2(char[] str, int i, int end, int outputPtr) { final byte[] outBuf = _outputBuffer; while (i < end) { int c = str[i++]; if (c <= 0x7F) { outBuf[outputPtr++] = (byte) c; continue; } // Nope, multi-byte: if (c < 0x800) { // 2-byte outBuf[outputPtr++] = (byte) (0xc0 | (c >> 6)); outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f)); continue; } // 3 or 4 bytes (surrogate) // Surrogates? if (c < SURR1_FIRST || c > SURR2_LAST) { // nope, regular 3-byte character outBuf[outputPtr++] = (byte) (0xe0 | (c >> 12)); outBuf[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f)); continue; } // Yup, a surrogate pair if (c > SURR1_LAST) { // must be from first range; second won't do _throwIllegalSurrogate(c); } // ... meaning it must have a pair if (i >= end) { _throwIllegalSurrogate(c); } c = _convertSurrogate(c, str[i++]); if (c > 0x10FFFF) { // illegal in JSON as well as in XML _throwIllegalSurrogate(c); } outBuf[outputPtr++] = (byte) (0xf0 | (c >> 18)); outBuf[outputPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); outBuf[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); outBuf[outputPtr++] = (byte) (0x80 | (c & 0x3f)); } int codedLen = outputPtr - _outputTail; _outputTail = outputPtr; return codedLen; } private void _slowUTF8Encode(String str) throws IOException { final int len = str.length(); int inputPtr = 0; final int bufferEnd = _outputEnd - 4; output_loop: for (; inputPtr < len; ) { /* First, let's ensure we can output at least 4 bytes * (longest UTF-8 encoded codepoint): */ if (_outputTail >= bufferEnd) { _flushBuffer(); } int c = str.charAt(inputPtr++); // And then see if we have an ASCII char: if (c <= 0x7F) { // If so, can do a tight inner loop: _outputBuffer[_outputTail++] = (byte)c; // Let's calc how many ASCII chars we can copy at most: int maxInCount = (len - inputPtr); int maxOutCount = (bufferEnd - _outputTail); if (maxInCount > maxOutCount) { maxInCount = maxOutCount; } maxInCount += inputPtr; ascii_loop: while (true) { if (inputPtr >= maxInCount) { // done with max. ascii seq continue output_loop; } c = str.charAt(inputPtr++); if (c > 0x7F) { break ascii_loop; } _outputBuffer[_outputTail++] = (byte) c; } } // Nope, multi-byte: if (c < 0x800) { // 2-byte _outputBuffer[_outputTail++] = (byte) (0xc0 | (c >> 6)); _outputBuffer[_outputTail++] = (byte) (0x80 | (c & 0x3f)); } else { // 3 or 4 bytes // Surrogates? if (c < SURR1_FIRST || c > SURR2_LAST) { _outputBuffer[_outputTail++] = (byte) (0xe0 | (c >> 12)); _outputBuffer[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f)); _outputBuffer[_outputTail++] = (byte) (0x80 | (c & 0x3f)); continue; } // Yup, a surrogate: if (c > SURR1_LAST) { // must be from first range _throwIllegalSurrogate(c); } // and if so, followed by another from next range if (inputPtr >= len) { _throwIllegalSurrogate(c); } c = _convertSurrogate(c, str.charAt(inputPtr++)); if (c > 0x10FFFF) { // illegal, as per RFC 4627 _throwIllegalSurrogate(c); } _outputBuffer[_outputTail++] = (byte) (0xf0 | (c >> 18)); _outputBuffer[_outputTail++] = (byte) (0x80 | ((c >> 12) & 0x3f)); _outputBuffer[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f)); _outputBuffer[_outputTail++] = (byte) (0x80 | (c & 0x3f)); } } } private void _mediumUTF8Encode(char[] str, int inputPtr, int inputEnd) throws IOException { final int bufferEnd = _outputEnd - 4; output_loop: while (inputPtr < inputEnd) { /* First, let's ensure we can output at least 4 bytes * (longest UTF-8 encoded codepoint): */ if (_outputTail >= bufferEnd) { _flushBuffer(); } int c = str[inputPtr++]; // And then see if we have an ASCII char: if (c <= 0x7F) { // If so, can do a tight inner loop: _outputBuffer[_outputTail++] = (byte)c; // Let's calc how many ASCII chars we can copy at most: int maxInCount = (inputEnd - inputPtr); int maxOutCount = (bufferEnd - _outputTail); if (maxInCount > maxOutCount) { maxInCount = maxOutCount; } maxInCount += inputPtr; ascii_loop: while (true) { if (inputPtr >= maxInCount) { // done with max. ascii seq continue output_loop; } c = str[inputPtr++]; if (c > 0x7F) { break ascii_loop; } _outputBuffer[_outputTail++] = (byte) c; } } // Nope, multi-byte: if (c < 0x800) { // 2-byte _outputBuffer[_outputTail++] = (byte) (0xc0 | (c >> 6)); _outputBuffer[_outputTail++] = (byte) (0x80 | (c & 0x3f)); } else { // 3 or 4 bytes // Surrogates? if (c < SURR1_FIRST || c > SURR2_LAST) { _outputBuffer[_outputTail++] = (byte) (0xe0 | (c >> 12)); _outputBuffer[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f)); _outputBuffer[_outputTail++] = (byte) (0x80 | (c & 0x3f)); continue; } // Yup, a surrogate: if (c > SURR1_LAST) { // must be from first range _throwIllegalSurrogate(c); } // and if so, followed by another from next range if (inputPtr >= inputEnd) { _throwIllegalSurrogate(c); } c = _convertSurrogate(c, str[inputPtr++]); if (c > 0x10FFFF) { // illegal, as per RFC 4627 _throwIllegalSurrogate(c); } _outputBuffer[_outputTail++] = (byte) (0xf0 | (c >> 18)); _outputBuffer[_outputTail++] = (byte) (0x80 | ((c >> 12) & 0x3f)); _outputBuffer[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f)); _outputBuffer[_outputTail++] = (byte) (0x80 | (c & 0x3f)); } } } /** * Method called to calculate UTF codepoint, from a surrogate pair. */ private int _convertSurrogate(int firstPart, int secondPart) { // Ok, then, is the second part valid? if (secondPart < SURR2_FIRST || secondPart > SURR2_LAST) { throw new IllegalArgumentException("Broken surrogate pair: first char 0x"+Integer.toHexString(firstPart)+", second 0x"+Integer.toHexString(secondPart)+"; illegal combination"); } return 0x10000 + ((firstPart - SURR1_FIRST) << 10) + (secondPart - SURR2_FIRST); } private void _throwIllegalSurrogate(int code) { if (code > 0x10FFFF) { // over max? throw new IllegalArgumentException("Illegal character point (0x"+Integer.toHexString(code)+") to output; max is 0x10FFFF as per RFC 4627"); } if (code >= SURR1_FIRST) { if (code <= SURR1_LAST) { // Unmatched first part (closing without second part?) throw new IllegalArgumentException("Unmatched first part of surrogate pair (0x"+Integer.toHexString(code)+")"); } throw new IllegalArgumentException("Unmatched second part of surrogate pair (0x"+Integer.toHexString(code)+")"); } // should we ever get this? throw new IllegalArgumentException("Illegal character point (0x"+Integer.toHexString(code)+") to output"); } /* /********************************************************** /* Internal methods, writing bytes /********************************************************** */ private final void _ensureRoomForOutput(int needed) throws IOException { if ((_outputTail + needed) >= _outputEnd) { _flushBuffer(); } } private final void _writeByte(byte b) throws IOException { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = b; } private final void _writeBytes(byte b1, byte b2) throws IOException { if ((_outputTail + 1) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b2; } private final void _writeBytes(byte b1, byte b2, byte b3) throws IOException { if ((_outputTail + 2) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b2; _outputBuffer[_outputTail++] = b3; } private final void _writeBytes(byte b1, byte b2, byte b3, byte b4) throws IOException { if ((_outputTail + 3) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b2; _outputBuffer[_outputTail++] = b3; _outputBuffer[_outputTail++] = b4; } private final void _writeBytes(byte b1, byte b2, byte b3, byte b4, byte b5) throws IOException { if ((_outputTail + 4) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b2; _outputBuffer[_outputTail++] = b3; _outputBuffer[_outputTail++] = b4; _outputBuffer[_outputTail++] = b5; } private final void _writeBytes(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6) throws IOException { if ((_outputTail + 5) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b2; _outputBuffer[_outputTail++] = b3; _outputBuffer[_outputTail++] = b4; _outputBuffer[_outputTail++] = b5; _outputBuffer[_outputTail++] = b6; } private final void _writeBytes(byte[] data, int offset, int len) throws IOException { if (len == 0) { return; } if ((_outputTail + len) >= _outputEnd) { _writeBytesLong(data, offset, len); return; } // common case, non-empty, fits in just fine: System.arraycopy(data, offset, _outputBuffer, _outputTail, len); _outputTail += len; } private final void _writeBytesLong(byte[] data, int offset, int len) throws IOException { if (_outputTail >= _outputEnd) { _flushBuffer(); } while (true) { int currLen = Math.min(len, (_outputEnd - _outputTail)); System.arraycopy(data, offset, _outputBuffer, _outputTail, currLen); _outputTail += currLen; if ((len -= currLen) == 0) { break; } offset += currLen; _flushBuffer(); } } /** * Helper method for writing a 32-bit positive (really 31-bit then) value. * Value is NOT zigzag encoded (since there is no sign bit to worry about) */ private void _writePositiveVInt(int i) throws IOException { // At most 5 bytes (4 * 7 + 6 bits == 34 bits) _ensureRoomForOutput(5); byte b0 = (byte) (0x80 + (i & 0x3F)); i >>= 6; if (i <= 0x7F) { // 6 or 13 bits is enough (== 2 or 3 byte total encoding) if (i > 0) { _outputBuffer[_outputTail++] = (byte) i; } _outputBuffer[_outputTail++] = b0; return; } byte b1 = (byte) (i & 0x7F); i >>= 7; if (i <= 0x7F) { _outputBuffer[_outputTail++] = (byte) i; _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b0; } else { byte b2 = (byte) (i & 0x7F); i >>= 7; if (i <= 0x7F) { _outputBuffer[_outputTail++] = (byte) i; _outputBuffer[_outputTail++] = b2; _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b0; } else { byte b3 = (byte) (i & 0x7F); _outputBuffer[_outputTail++] = (byte) (i >> 7); _outputBuffer[_outputTail++] = b3; _outputBuffer[_outputTail++] = b2; _outputBuffer[_outputTail++] = b1; _outputBuffer[_outputTail++] = b0; } } } /** * Helper method for writing 32-bit signed value, using * "zig zag encoding" (see protocol buffers for explanation -- basically, * sign bit is moved as LSB, rest of value shifted left by one) * coupled with basic variable length encoding */ private void _writeSignedVInt(int input) throws IOException { _writePositiveVInt(SmileUtil.zigzagEncode(input)); } protected void _write7BitBinaryWithLength(byte[] data, int offset, int len) throws IOException { _writePositiveVInt(len); // first, let's handle full 7-byte chunks while (len >= 7) { if ((_outputTail + 8) >= _outputEnd) { _flushBuffer(); } int i = data[offset++]; // 1st byte _outputBuffer[_outputTail++] = (byte) ((i >> 1) & 0x7F); i = (i << 8) | (data[offset++] & 0xFF); // 2nd _outputBuffer[_outputTail++] = (byte) ((i >> 2) & 0x7F); i = (i << 8) | (data[offset++] & 0xFF); // 3rd _outputBuffer[_outputTail++] = (byte) ((i >> 3) & 0x7F); i = (i << 8) | (data[offset++] & 0xFF); // 4th _outputBuffer[_outputTail++] = (byte) ((i >> 4) & 0x7F); i = (i << 8) | (data[offset++] & 0xFF); // 5th _outputBuffer[_outputTail++] = (byte) ((i >> 5) & 0x7F); i = (i << 8) | (data[offset++] & 0xFF); // 6th _outputBuffer[_outputTail++] = (byte) ((i >> 6) & 0x7F); i = (i << 8) | (data[offset++] & 0xFF); // 7th _outputBuffer[_outputTail++] = (byte) ((i >> 7) & 0x7F); _outputBuffer[_outputTail++] = (byte) (i & 0x7F); len -= 7; } // and then partial piece, if any if (len > 0) { // up to 6 bytes to output, resulting in at most 7 bytes (which can encode 49 bits) if ((_outputTail + 7) >= _outputEnd) { _flushBuffer(); } int i = data[offset++]; _outputBuffer[_outputTail++] = (byte) ((i >> 1) & 0x7F); if (len > 1) { i = ((i & 0x01) << 8) | (data[offset++] & 0xFF); // 2nd _outputBuffer[_outputTail++] = (byte) ((i >> 2) & 0x7F); if (len > 2) { i = ((i & 0x03) << 8) | (data[offset++] & 0xFF); // 3rd _outputBuffer[_outputTail++] = (byte) ((i >> 3) & 0x7F); if (len > 3) { i = ((i & 0x07) << 8) | (data[offset++] & 0xFF); // 4th _outputBuffer[_outputTail++] = (byte) ((i >> 4) & 0x7F); if (len > 4) { i = ((i & 0x0F) << 8) | (data[offset++] & 0xFF); // 5th _outputBuffer[_outputTail++] = (byte) ((i >> 5) & 0x7F); if (len > 5) { i = ((i & 0x1F) << 8) | (data[offset++] & 0xFF); // 6th _outputBuffer[_outputTail++] = (byte) ((i >> 6) & 0x7F); _outputBuffer[_outputTail++] = (byte) (i & 0x3F); // last 6 bits } else { _outputBuffer[_outputTail++] = (byte) (i & 0x1F); // last 5 bits } } else { _outputBuffer[_outputTail++] = (byte) (i & 0x0F); // last 4 bits } } else { _outputBuffer[_outputTail++] = (byte) (i & 0x07); // last 3 bits } } else { _outputBuffer[_outputTail++] = (byte) (i & 0x03); // last 2 bits } } else { _outputBuffer[_outputTail++] = (byte) (i & 0x01); // last bit } } } /* /********************************************************** /* Internal methods, buffer handling /********************************************************** */ @Override protected void _releaseBuffers() { byte[] buf = _outputBuffer; if (buf != null && _bufferRecyclable) { _outputBuffer = null; _ioContext.releaseWriteEncodingBuffer(buf); } char[] cbuf = _charBuffer; if (cbuf != null) { _charBuffer = null; _ioContext.releaseConcatBuffer(cbuf); } /* Ok: since clearing up of larger arrays is much slower, * let's only recycle default-sized buffers... */ { SharedStringNode[] nameBuf = _seenNames; if (nameBuf != null && nameBuf.length == SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH) { _seenNames = null; /* 28-Jun-2011, tatu: With 1.9, caller needs to clear the buffer; and note * that since it's a hash area, must clear all */ if (_seenNameCount > 0) { Arrays.fill(nameBuf, null); } _smileBufferRecycler.releaseSeenNamesBuffer(nameBuf); } } { SharedStringNode[] valueBuf = _seenStringValues; if (valueBuf != null && valueBuf.length == SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH) { _seenStringValues = null; /* 28-Jun-2011, tatu: With 1.9, caller needs to clear the buffer; and note * that since it's a hash area, must clear all */ if (_seenStringValueCount > 0) { Arrays.fill(valueBuf, null); } _smileBufferRecycler.releaseSeenStringValuesBuffer(valueBuf); } } } protected final void _flushBuffer() throws IOException { if (_outputTail > 0) { _bytesWritten += _outputTail; _out.write(_outputBuffer, 0, _outputTail); _outputTail = 0; } } /* /********************************************************** /* Internal methods, handling shared string "maps" /********************************************************** */ private final int _findSeenName(String name) { int hash = name.hashCode(); SharedStringNode head = _seenNames[hash & (_seenNames.length-1)]; if (head == null) { return -1; } SharedStringNode node = head; // first, identity match; assuming most of the time we get intern()ed String // And do unrolled initial check; 90+% likelihood head node has all info we need: if (node.value == name) { return node.index; } while ((node = node.next) != null) { if (node.value == name) { return node.index; } } // If not, equality check; we already know head is not null node = head; do { String value = node.value; if (value.hashCode() == hash && value.equals(name)) { return node.index; } node = node.next; } while (node != null); return -1; } private final void _addSeenName(String name) { // first: do we need to expand? if (_seenNameCount == _seenNames.length) { if (_seenNameCount == MAX_SHARED_NAMES) { // we are too full, restart from empty Arrays.fill(_seenNames, null); _seenNameCount = 0; } else { // we always start with modest default size (like 64), so expand to full SharedStringNode[] old = _seenNames; _seenNames = new SharedStringNode[MAX_SHARED_NAMES]; final int mask = MAX_SHARED_NAMES-1; for (SharedStringNode node : old) { for (; node != null; node = node.next) { int ix = node.value.hashCode() & mask; node.next = _seenNames[ix]; _seenNames[ix] = node; } } } } // other than that, just slap it there int ix = name.hashCode() & (_seenNames.length-1); _seenNames[ix] = new SharedStringNode(name, _seenNameCount, _seenNames[ix]); ++_seenNameCount; } private final int _findSeenStringValue(String text) { int hash = text.hashCode(); SharedStringNode head = _seenStringValues[hash & (_seenStringValues.length-1)]; if (head != null) { SharedStringNode node = head; // first, identity match; assuming most of the time we get intern()ed String do { if (node.value == text) { return node.index; } node = node.next; } while (node != null); // and then comparison, if no match yet node = head; do { String value = node.value; if (value.hashCode() == hash && value.equals(text)) { return node.index; } node = node.next; } while (node != null); } return -1; } private final void _addSeenStringValue(String text) { // first: do we need to expand? if (_seenStringValueCount == _seenStringValues.length) { if (_seenStringValueCount == MAX_SHARED_STRING_VALUES) { // we are too full, restart from empty Arrays.fill(_seenStringValues, null); _seenStringValueCount = 0; } else { // we always start with modest default size (like 64), so expand to full SharedStringNode[] old = _seenStringValues; _seenStringValues = new SharedStringNode[MAX_SHARED_STRING_VALUES]; final int mask = MAX_SHARED_STRING_VALUES-1; for (SharedStringNode node : old) { for (; node != null; node = node.next) { int ix = node.value.hashCode() & mask; node.next = _seenStringValues[ix]; _seenStringValues[ix] = node; } } } } // other than that, just slap it there int ix = text.hashCode() & (_seenStringValues.length-1); _seenStringValues[ix] = new SharedStringNode(text, _seenStringValueCount, _seenStringValues[ix]); ++_seenStringValueCount; } /* /********************************************************** /* Internal methods, error reporting /********************************************************** */ /** * Method for accessing offset of the next byte within the whole output * stream that this generator has produced. */ protected long outputOffset() { return _bytesWritten + _outputTail; } protected UnsupportedOperationException _notSupported() { return new UnsupportedOperationException(); } } jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/Tool.java0000644000175000017500000001275111655120726026151 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; import java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.smile.SmileFactory; /** * Simple command-line utility that can be used to encode JSON as Smile, or * decode JSON from Smile: direction is indicated by single command-line * option of either "-e" (encode) or "-d" (decode). * * @author tatu * * @since 1.6.2 */ public class Tool { public final static String SUFFIX = ".lzf"; public final JsonFactory jsonFactory; public final SmileFactory smileFactory; public Tool() { jsonFactory = new JsonFactory(); smileFactory = new SmileFactory(); // check all shared refs (-> small size); add header, not trailing marker; do not use raw binary smileFactory.configure(SmileGenerator.Feature.CHECK_SHARED_NAMES, true); smileFactory.configure(SmileGenerator.Feature.CHECK_SHARED_STRING_VALUES, true); smileFactory.configure(SmileGenerator.Feature.ENCODE_BINARY_AS_7BIT, true); smileFactory.configure(SmileGenerator.Feature.WRITE_HEADER, true); smileFactory.configure(SmileGenerator.Feature.WRITE_END_MARKER, false); // also: do not require header smileFactory.configure(SmileParser.Feature.REQUIRE_HEADER, false); } private void process(String[] args) throws IOException { String oper = null; String filename = null; if (args.length == 2) { oper = args[0]; filename = args[1]; } else if (args.length == 1) { oper = args[0]; } else { showUsage(); } boolean encode = "-e".equals(oper); if (encode) { encode(inputStream(filename)); } else if ("-d".equals(oper)) { decode(inputStream(filename)); } else if ("-v".equals(oper)) { // need to read twice (encode, verify/compare) verify(inputStream(filename), inputStream(filename)); } else { showUsage(); } } private InputStream inputStream(String filename) throws IOException { // if no argument given, read from stdin if (filename == null) { return System.in; } File src = new File(filename); if (!src.exists()) { System.err.println("File '"+filename+"' does not exist."); System.exit(1); } return new FileInputStream(src); } private void decode(InputStream in) throws IOException { JsonParser jp = smileFactory.createJsonParser(in); JsonGenerator jg = jsonFactory.createJsonGenerator(System.out, JsonEncoding.UTF8); while (true) { /* Just one trick: since Smile can have segments (multiple 'documents' in output * stream), we should not stop at first end marker, only bail out if two are seen */ if (jp.nextToken() == null) { if (jp.nextToken() == null) { break; } } jg.copyCurrentEvent(jp); } jp.close(); jg.close(); } private void encode(InputStream in) throws IOException { JsonParser jp = jsonFactory.createJsonParser(in); JsonGenerator jg = smileFactory.createJsonGenerator(System.out, JsonEncoding.UTF8); while ((jp.nextToken()) != null) { jg.copyCurrentEvent(jp); } jp.close(); jg.close(); } private void verify(InputStream in, InputStream in2) throws IOException { JsonParser jp = jsonFactory.createJsonParser(in); ByteArrayOutputStream bytes = new ByteArrayOutputStream(4000); JsonGenerator jg = smileFactory.createJsonGenerator(bytes, JsonEncoding.UTF8); // First, read, encode in memory buffer while ((jp.nextToken()) != null) { jg.copyCurrentEvent(jp); } jp.close(); jg.close(); // and then re-read both, verify jp = jsonFactory.createJsonParser(in2); byte[] smile = bytes.toByteArray(); JsonParser jp2 = smileFactory.createJsonParser(smile); JsonToken t; int count = 0; while ((t = jp.nextToken()) != null) { JsonToken t2 = jp2.nextToken(); ++count; if (t != t2) { throw new IOException("Input and encoded differ, token #"+count+"; expected "+t+", got "+t2); } // also, need to have same texts... String text1 = jp.getText(); String text2 = jp2.getText(); if (!text1.equals(text2)) { throw new IOException("Input and encoded differ, token #"+count+"; expected text '"+text1+"', got '"+text2+"'"); } } System.out.println("OK: verified "+count+" tokens (from "+smile.length+" bytes of Smile encoded data), input and encoded contents are identical"); } protected void showUsage() { System.err.println("Usage: java "+getClass().getName()+" -e/-d [file]"); System.err.println(" (if no file given, reads from stdin -- always writes to stdout)"); System.err.println(" -d: decode Smile encoded input as JSON"); System.err.println(" -e: encode JSON (text) input as Smile"); System.err.println(" -v: encode JSON (text) input as Smile; read back, verify, do not write out"); System.exit(1); } public static void main(String[] args) throws IOException { new Tool().process(args); } } jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/SmileFactory.java0000644000175000017500000003036711655120726027640 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; import java.io.*; import java.net.URL; import org.codehaus.jackson.*; import org.codehaus.jackson.format.InputAccessor; import org.codehaus.jackson.format.MatchStrength; import org.codehaus.jackson.io.IOContext; /** * Factory used for constructing {@link SmileParser} and {@link SmileGenerator} * instances; both of which handle * Smile encoded data. *

* Extends {@link JsonFactory} mostly so that users can actually use it in place * of regular non-Smile factory instances. *

* Note on using non-byte-based sources/targets (char based, like * {@link java.io.Reader} and {@link java.io.Writer}): these can not be * used for Smile-format documents, and thus will either downgrade to * textual JSON (when parsing), or throw exception (when trying to create * generator). * * @author tatu * * @since 1.6 */ public class SmileFactory extends JsonFactory { /** * Name used to identify Smile format. * (and returned by {@link #getFormatName()} */ public final static String FORMAT_NAME_SMILE = "Smile"; /** * Bitfield (set of flags) of all parser features that are enabled * by default. */ final static int DEFAULT_SMILE_PARSER_FEATURE_FLAGS = SmileParser.Feature.collectDefaults(); /** * Bitfield (set of flags) of all generator features that are enabled * by default. */ final static int DEFAULT_SMILE_GENERATOR_FEATURE_FLAGS = SmileGenerator.Feature.collectDefaults(); /* /********************************************************** /* Configuration /********************************************************** */ /** * Whether non-supported methods (ones trying to output using * char-based targets like {@link java.io.Writer}, for example) * should be delegated to regular Jackson JSON processing * (if set to true); or throw {@link UnsupportedOperationException} * (if set to false) */ protected boolean _cfgDelegateToTextual; protected int _smileParserFeatures = DEFAULT_SMILE_PARSER_FEATURE_FLAGS; protected int _smileGeneratorFeatures = DEFAULT_SMILE_GENERATOR_FEATURE_FLAGS; /* /********************************************************** /* Factory construction, configuration /********************************************************** */ /** * Default constructor used to create factory instances. * Creation of a factory instance is a light-weight operation, * but it is still a good idea to reuse limited number of * factory instances (and quite often just a single instance): * factories are used as context for storing some reused * processing objects (such as symbol tables parsers use) * and this reuse only works within context of a single * factory instance. */ public SmileFactory() { this(null); } public SmileFactory(ObjectCodec oc) { super(oc); } public void delegateToTextual(boolean state) { _cfgDelegateToTextual = state; } /* /********************************************************** /* Format detection functionality (since 1.8) /********************************************************** */ @Override public String getFormatName() { return FORMAT_NAME_SMILE; } /** * Sub-classes need to override this method (as of 1.8) */ @Override public MatchStrength hasFormat(InputAccessor acc) throws IOException { return SmileParserBootstrapper.hasSmileFormat(acc); } /* /********************************************************** /* Configuration, parser settings /********************************************************** */ /** * Method for enabling or disabling specified parser feature * (check {@link SmileParser.Feature} for list of features) */ public final SmileFactory configure(SmileParser.Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; } /** * Method for enabling specified parser feature * (check {@link SmileParser.Feature} for list of features) */ public SmileFactory enable(SmileParser.Feature f) { _smileParserFeatures |= f.getMask(); return this; } /** * Method for disabling specified parser features * (check {@link SmileParser.Feature} for list of features) */ public SmileFactory disable(SmileParser.Feature f) { _smileParserFeatures &= ~f.getMask(); return this; } /** * Checked whether specified parser feature is enabled. */ public final boolean isEnabled(SmileParser.Feature f) { return (_smileParserFeatures & f.getMask()) != 0; } /* /********************************************************** /* Configuration, generator settings /********************************************************** */ /** * Method for enabling or disabling specified generator feature * (check {@link org.codehaus.jackson.JsonGenerator.Feature} for list of features) * * @since 1.2 */ public final SmileFactory configure(SmileGenerator.Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; } /** * Method for enabling specified generator features * (check {@link org.codehaus.jackson.JsonGenerator.Feature} for list of features) */ public SmileFactory enable(SmileGenerator.Feature f) { _smileGeneratorFeatures |= f.getMask(); return this; } /** * Method for disabling specified generator feature * (check {@link org.codehaus.jackson.JsonGenerator.Feature} for list of features) */ public SmileFactory disable(SmileGenerator.Feature f) { _smileGeneratorFeatures &= ~f.getMask(); return this; } /** * Check whether specified generator feature is enabled. */ public final boolean isEnabled(SmileGenerator.Feature f) { return (_smileGeneratorFeatures & f.getMask()) != 0; } /* /********************************************************** /* Overridden parser factory methods /********************************************************** */ @Override public SmileParser createJsonParser(File f) throws IOException, JsonParseException { return _createJsonParser(new FileInputStream(f), _createContext(f, true)); } @Override public SmileParser createJsonParser(URL url) throws IOException, JsonParseException { return _createJsonParser(_optimizedStreamFromURL(url), _createContext(url, true)); } @Override public SmileParser createJsonParser(InputStream in) throws IOException, JsonParseException { return _createJsonParser(in, _createContext(in, false)); } //public JsonParser createJsonParser(Reader r) @Override public SmileParser createJsonParser(byte[] data) throws IOException, JsonParseException { IOContext ctxt = _createContext(data, true); return _createJsonParser(data, 0, data.length, ctxt); } @Override public SmileParser createJsonParser(byte[] data, int offset, int len) throws IOException, JsonParseException { return _createJsonParser(data, offset, len, _createContext(data, true)); } /* /********************************************************** /* Overridden generator factory methods /********************************************************** */ /** *

* note: co-variant return type */ @Override public SmileGenerator createJsonGenerator(OutputStream out, JsonEncoding enc) throws IOException { return createJsonGenerator(out); } /** * Since Smile format always uses UTF-8 internally, no encoding need * to be passed to this method. */ @Override public SmileGenerator createJsonGenerator(OutputStream out) throws IOException { // false -> we won't manage the stream unless explicitly directed to IOContext ctxt = _createContext(out, false); return _createJsonGenerator(out, ctxt); } /* /****************************************************** /* Overridden internal factory methods /****************************************************** */ //protected IOContext _createContext(Object srcRef, boolean resourceManaged) /** * Overridable factory method that actually instantiates desired * parser. */ @Override protected SmileParser _createJsonParser(InputStream in, IOContext ctxt) throws IOException, JsonParseException { return new SmileParserBootstrapper(ctxt, in).constructParser(_parserFeatures, _smileParserFeatures, _objectCodec, _rootByteSymbols); } /** * Overridable factory method that actually instantiates desired * parser. */ @Override protected JsonParser _createJsonParser(Reader r, IOContext ctxt) throws IOException, JsonParseException { if (_cfgDelegateToTextual) { return super._createJsonParser(r, ctxt); } throw new UnsupportedOperationException("Can not create generator for non-byte-based target"); } /** * Overridable factory method that actually instantiates desired * parser. */ @Override protected SmileParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException, JsonParseException { return new SmileParserBootstrapper(ctxt, data, offset, len).constructParser(_parserFeatures, _smileParserFeatures, _objectCodec, _rootByteSymbols); } /** * Overridable factory method that actually instantiates desired * generator. */ @Override protected JsonGenerator _createJsonGenerator(Writer out, IOContext ctxt) throws IOException { if (_cfgDelegateToTextual) { return super._createJsonGenerator(out, ctxt); } throw new UnsupportedOperationException("Can not create generator for non-byte-based target"); } //public BufferRecycler _getBufferRecycler() @Override protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException { if (_cfgDelegateToTextual) { return super._createWriter(out, enc, ctxt); } throw new UnsupportedOperationException("Can not create generator for non-byte-based target"); } /* /********************************************************** /* Internal methods /********************************************************** */ protected SmileGenerator _createJsonGenerator(OutputStream out, IOContext ctxt) throws IOException { int feats = _smileGeneratorFeatures; /* One sanity check: MUST write header if shared string values setting is enabled, * or quoting of binary data disabled. * But should we force writing, or throw exception, if settings are in conflict? * For now, let's error out... */ SmileGenerator gen = new SmileGenerator(ctxt, _generatorFeatures, feats, _objectCodec, out); if ((feats & SmileGenerator.Feature.WRITE_HEADER.getMask()) != 0) { gen.writeHeader(); } else { if ((feats & SmileGenerator.Feature.CHECK_SHARED_STRING_VALUES.getMask()) != 0) { throw new JsonGenerationException( "Inconsistent settings: WRITE_HEADER disabled, but CHECK_SHARED_STRING_VALUES enabled; can not construct generator" +" due to possible data loss (either enable WRITE_HEADER, or disable CHECK_SHARED_STRING_VALUES to resolve)"); } if ((feats & SmileGenerator.Feature.ENCODE_BINARY_AS_7BIT.getMask()) == 0) { throw new JsonGenerationException( "Inconsistent settings: WRITE_HEADER disabled, but ENCODE_BINARY_AS_7BIT disabled; can not construct generator" +" due to possible data loss (either enable WRITE_HEADER, or ENCODE_BINARY_AS_7BIT to resolve)"); } } return gen; } } jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/package-info.java0000644000175000017500000000053311655120726027553 0ustar jamespagejamespage/** * Package that contains experimental implementation of * "Binary-Encoded JSON-Like" data format handlers (parser, * generator, factory produce both, supporting constants). *

* See Smile format specification for more details. * * @since 1.6 */ package org.codehaus.jackson.smile; jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/SmileParser.java0000644000175000017500000025747011655120726027473 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; import static org.codehaus.jackson.smile.SmileConstants.BYTE_MARKER_END_OF_STRING; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.SoftReference; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import org.codehaus.jackson.*; import org.codehaus.jackson.impl.JsonParserBase; import org.codehaus.jackson.io.IOContext; import org.codehaus.jackson.sym.BytesToNameCanonicalizer; import org.codehaus.jackson.sym.Name; public class SmileParser extends JsonParserBase { /** * Enumeration that defines all togglable features for Smile generators. */ public enum Feature { /** * Feature that determines whether 4-byte Smile header is mandatory in input, * or optional. If enabled, it means that only input that starts with the header * is accepted as valid; if disabled, header is optional. In latter case,r * settings for content are assumed to be defaults. */ REQUIRE_HEADER(true) ; final boolean _defaultState; final int _mask; /** * Method that calculates bit set (flags) of all features that * are enabled by default. */ public static int collectDefaults() { int flags = 0; for (Feature f : values()) { if (f.enabledByDefault()) { flags |= f.getMask(); } } return flags; } private Feature(boolean defaultState) { _defaultState = defaultState; _mask = (1 << ordinal()); } public boolean enabledByDefault() { return _defaultState; } public int getMask() { return _mask; } } private final static int[] NO_INTS = new int[0]; private final static String[] NO_STRINGS = new String[0]; /* /********************************************************** /* Configuration /********************************************************** */ /** * Codec used for data binding when (if) requested. */ protected ObjectCodec _objectCodec; /** * Flag that indicates whether content can legally have raw (unquoted) * binary data. Since this information is included both in header and * in actual binary data blocks there is redundancy, and we want to * ensure settings are compliant. Using application may also want to * know this setting in case it does some direct (random) access. */ protected boolean _mayContainRawBinary; /** * Helper object used for low-level recycling of Smile-generator * specific buffers. * * @since 1.7 */ final protected SmileBufferRecycler _smileBufferRecycler; /* /********************************************************** /* Input source config, state (from ex StreamBasedParserBase) /********************************************************** */ /** * Input stream that can be used for reading more content, if one * in use. May be null, if input comes just as a full buffer, * or if the stream has been closed. */ protected InputStream _inputStream; /** * Current buffer from which data is read; generally data is read into * buffer from input source, but in some cases pre-loaded buffer * is handed to the parser. */ protected byte[] _inputBuffer; /** * Flag that indicates whether the input buffer is recycable (and * needs to be returned to recycler once we are done) or not. *

* If it is not, it also means that parser can NOT modify underlying * buffer. */ protected boolean _bufferRecyclable; /* /********************************************************** /* Additional parsing state /********************************************************** */ /** * Flag that indicates that the current token has not yet * been fully processed, and needs to be finished for * some access (or skipped to obtain the next token) */ protected boolean _tokenIncomplete = false; /** * Type byte of the current token */ protected int _typeByte; /** * Specific flag that is set when we encountered a 32-bit * floating point value; needed since numeric super classes do * not track distinction between float and double, but Smile * format does, and we want to retain that separation. */ protected boolean _got32BitFloat; /* /********************************************************** /* Symbol handling, decoding /********************************************************** */ /** * Symbol table that contains field names encountered so far */ final protected BytesToNameCanonicalizer _symbols; /** * Temporary buffer used for name parsing. */ protected int[] _quadBuffer = NO_INTS; /** * Quads used for hash calculation */ protected int _quad1, _quad2; /** * Array of recently seen field names, which may be back referenced * by later fields. * Defaults set to enable handling even if no header found. */ protected String[] _seenNames = NO_STRINGS; protected int _seenNameCount = 0; /** * Array of recently seen field names, which may be back referenced * by later fields * Defaults set to disable handling if no header found. */ protected String[] _seenStringValues = null; protected int _seenStringValueCount = -1; /* /********************************************************** /* Thread-local recycling /********************************************************** */ /** * ThreadLocal contains a {@link java.lang.ref.SoftRerefence} * to a buffer recycler used to provide a low-cost * buffer recycling for Smile-specific buffers. */ final protected static ThreadLocal>> _smileRecyclerRef = new ThreadLocal>>(); /* /********************************************************** /* Life-cycle /********************************************************** */ public SmileParser(IOContext ctxt, int parserFeatures, int smileFeatures, ObjectCodec codec, BytesToNameCanonicalizer sym, InputStream in, byte[] inputBuffer, int start, int end, boolean bufferRecyclable) { super(ctxt, parserFeatures); _objectCodec = codec; _symbols = sym; _inputStream = in; _inputBuffer = inputBuffer; _inputPtr = start; _inputEnd = end; _bufferRecyclable = bufferRecyclable; _tokenInputRow = -1; _tokenInputCol = -1; _smileBufferRecycler = _smileBufferRecycler(); } @Override public ObjectCodec getCodec() { return _objectCodec; } @Override public void setCodec(ObjectCodec c) { _objectCodec = c; } /** * Helper method called when it looks like input might contain the signature; * and it is necessary to detect and handle signature to get configuration * information it might have. * * @return True if valid signature was found and handled; false if not */ protected boolean handleSignature(boolean consumeFirstByte, boolean throwException) throws IOException, JsonParseException { if (consumeFirstByte) { ++_inputPtr; } if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } if (_inputBuffer[_inputPtr] != SmileConstants.HEADER_BYTE_2) { if (throwException) { _reportError("Malformed content: signature not valid, starts with 0x3a but followed by 0x" +Integer.toHexString(_inputBuffer[_inputPtr])+", not 0x29"); } return false; } if (++_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } if (_inputBuffer[_inputPtr] != SmileConstants.HEADER_BYTE_3) { if (throwException) { _reportError("Malformed content: signature not valid, starts with 0x3a, 0x29, but followed by 0x" +Integer.toHexString(_inputBuffer[_inputPtr])+", not 0xA"); } return false; } // Good enough; just need version info from 4th byte... if (++_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int ch = _inputBuffer[_inputPtr++]; int versionBits = (ch >> 4) & 0x0F; // but failure with version number is fatal, can not ignore if (versionBits != SmileConstants.HEADER_VERSION_0) { _reportError("Header version number bits (0x"+Integer.toHexString(versionBits)+") indicate unrecognized version; only 0x0 handled by parser"); } // can avoid tracking names, if explicitly disabled if ((ch & SmileConstants.HEADER_BIT_HAS_SHARED_NAMES) == 0) { _seenNames = null; _seenNameCount = -1; } // conversely, shared string values must be explicitly enabled if ((ch & SmileConstants.HEADER_BIT_HAS_SHARED_STRING_VALUES) != 0) { _seenStringValues = NO_STRINGS; _seenStringValueCount = 0; } _mayContainRawBinary = ((ch & SmileConstants.HEADER_BIT_HAS_RAW_BINARY) != 0); return true; } /** * @since 1.7 */ protected final static SmileBufferRecycler _smileBufferRecycler() { SoftReference> ref = _smileRecyclerRef.get(); SmileBufferRecycler br = (ref == null) ? null : ref.get(); if (br == null) { br = new SmileBufferRecycler(); _smileRecyclerRef.set(new SoftReference>(br)); } return br; } /* /********************************************************** /* Former StreamBasedParserBase methods /********************************************************** */ @Override public int releaseBuffered(OutputStream out) throws IOException { int count = _inputEnd - _inputPtr; if (count < 1) { return 0; } // let's just advance ptr to end int origPtr = _inputPtr; out.write(_inputBuffer, origPtr, count); return count; } @Override public Object getInputSource() { return _inputStream; } /** * Overridden since we do not really have character-based locations, * but we do have byte offset to specify. */ @Override public JsonLocation getTokenLocation() { return new JsonLocation(_ioContext.getSourceReference(), _tokenInputTotal, // bytes -1, -1, -1); // char offset, line, column } /** * Overridden since we do not really have character-based locations, * but we do have byte offset to specify. */ @Override public JsonLocation getCurrentLocation() { return new JsonLocation(_ioContext.getSourceReference(), _currInputProcessed + _inputPtr, // bytes -1, -1, -1); // char offset, line, column } /* /********************************************************** /* Low-level reading, other /********************************************************** */ @Override protected final boolean loadMore() throws IOException { _currInputProcessed += _inputEnd; //_currInputRowStart -= _inputEnd; if (_inputStream != null) { int count = _inputStream.read(_inputBuffer, 0, _inputBuffer.length); if (count > 0) { _inputPtr = 0; _inputEnd = count; return true; } // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes"); } } return false; } /** * Helper method that will try to load at least specified number bytes in * input buffer, possible moving existing data around if necessary * * @since 1.6 */ protected final boolean _loadToHaveAtLeast(int minAvailable) throws IOException { // No input stream, no leading (either we are closed, or have non-stream input source) if (_inputStream == null) { return false; } // Need to move remaining data in front? int amount = _inputEnd - _inputPtr; if (amount > 0 && _inputPtr > 0) { _currInputProcessed += _inputPtr; //_currInputRowStart -= _inputPtr; System.arraycopy(_inputBuffer, _inputPtr, _inputBuffer, 0, amount); _inputEnd = amount; } else { _inputEnd = 0; } _inputPtr = 0; while (_inputEnd < minAvailable) { int count = _inputStream.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd); if (count < 1) { // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("InputStream.read() returned 0 characters when trying to read "+amount+" bytes"); } return false; } _inputEnd += count; } return true; } @Override protected void _closeInput() throws IOException { /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying InputStream, unless we "own" it, or auto-closing * feature is enabled. */ if (_inputStream != null) { if (_ioContext.isResourceManaged() || isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE)) { _inputStream.close(); } _inputStream = null; } } /* /********************************************************** /* Overridden methods /********************************************************** */ @Override protected void _finishString() throws IOException, JsonParseException { // should never be called; but must be defined for superclass _throwInternal(); } @Override public void close() throws IOException { super.close(); // Merge found symbols, if any: _symbols.release(); } @Override public boolean hasTextCharacters() { if (_currToken == JsonToken.VALUE_STRING) { // yes; is or can be made available efficiently as char[] return _textBuffer.hasTextAsCharacters(); } if (_currToken == JsonToken.FIELD_NAME) { // not necessarily; possible but: return _nameCopied; } // other types, no benefit from accessing as char[] return false; } /** * Method called to release internal buffers owned by the base * reader. This may be called along with {@link #_closeInput} (for * example, when explicitly closing this reader instance), or * separately (if need be). */ @Override protected void _releaseBuffers() throws IOException { super._releaseBuffers(); if (_bufferRecyclable) { byte[] buf = _inputBuffer; if (buf != null) { _inputBuffer = null; _ioContext.releaseReadIOBuffer(buf); } } { String[] nameBuf = _seenNames; if (nameBuf != null && nameBuf.length > 0) { _seenNames = null; /* 28-Jun-2011, tatu: With 1.9, caller needs to clear the buffer; * but we only need to clear up to count as it is not a hash area */ if (_seenNameCount > 0) { Arrays.fill(nameBuf, 0, _seenNameCount, null); } _smileBufferRecycler.releaseSeenNamesBuffer(nameBuf); } } { String[] valueBuf = _seenStringValues; if (valueBuf != null && valueBuf.length > 0) { _seenStringValues = null; /* 28-Jun-2011, tatu: With 1.9, caller needs to clear the buffer; * but we only need to clear up to count as it is not a hash area */ if (_seenStringValueCount > 0) { Arrays.fill(valueBuf, 0, _seenStringValueCount, null); } _smileBufferRecycler.releaseSeenStringValuesBuffer(valueBuf); } } } /* /********************************************************** /* Extended API /********************************************************** */ public boolean mayContainRawBinary() { return _mayContainRawBinary; } /* /********************************************************** /* JsonParser impl /********************************************************** */ @Override public JsonToken nextToken() throws IOException, JsonParseException { _numTypesValid = NR_UNKNOWN; // For longer tokens (text, binary), we'll only read when requested if (_tokenIncomplete) { _skipIncomplete(); } _tokenInputTotal = _currInputProcessed + _inputPtr; // also: clear any data retained so far _binaryValue = null; // Two main modes: values, and field names. if (_parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) { return (_currToken = _handleFieldName()); } if (_inputPtr >= _inputEnd) { if (!loadMore()) { _handleEOF(); /* NOTE: here we can and should close input, release buffers, * since this is "hard" EOF, not a boundary imposed by * header token. */ close(); return (_currToken = null); } } int ch = _inputBuffer[_inputPtr++]; _typeByte = ch; switch ((ch >> 5) & 0x7) { case 0: // short shared string value reference if (ch == 0) { // important: this is invalid, don't accept _reportError("Invalid token byte 0x00"); } return _handleSharedString(ch-1); case 1: // simple literals, numbers { int typeBits = ch & 0x1F; if (typeBits < 4) { switch (typeBits) { case 0x00: _textBuffer.resetWithEmpty(); return (_currToken = JsonToken.VALUE_STRING); case 0x01: return (_currToken = JsonToken.VALUE_NULL); case 0x02: // false return (_currToken = JsonToken.VALUE_FALSE); default: // 0x03 == true return (_currToken = JsonToken.VALUE_TRUE); } } // next 3 bytes define subtype if (typeBits < 8) { // VInt (zigzag), BigInteger if ((typeBits & 0x3) <= 0x2) { // 0x3 reserved (should never occur) _tokenIncomplete = true; _numTypesValid = 0; return (_currToken = JsonToken.VALUE_NUMBER_INT); } break; } if (typeBits < 12) { // floating-point int subtype = typeBits & 0x3; if (subtype <= 0x2) { // 0x3 reserved (should never occur) _tokenIncomplete = true; _numTypesValid = 0; _got32BitFloat = (subtype == 0); return (_currToken = JsonToken.VALUE_NUMBER_FLOAT); } break; } if (typeBits == 0x1A) { // == 0x3A == ':' -> possibly header signature for next chunk? if (handleSignature(false, false)) { /* Ok, now; end-marker and header both imply doc boundary and a * 'null token'; but if both are seen, they are collapsed. * We can check this by looking at current token; if it's null, * need to get non-null token */ if (_currToken == null) { return nextToken(); } return (_currToken = null); } } _reportError("Unrecognized token byte 0x3A (malformed segment header?"); } // and everything else is reserved, for now break; case 2: // tiny ASCII // fall through case 3: // short ASCII // fall through case 4: // tiny Unicode // fall through case 5: // short Unicode // No need to decode, unless we have to keep track of back-references (for shared string values) _currToken = JsonToken.VALUE_STRING; if (_seenStringValueCount >= 0) { // shared text values enabled _addSeenStringValue(); } else { _tokenIncomplete = true; } return _currToken; case 6: // small integers; zigzag encoded _numberInt = SmileUtil.zigzagDecode(ch & 0x1F); _numTypesValid = NR_INT; return (_currToken = JsonToken.VALUE_NUMBER_INT); case 7: // binary/long-text/long-shared/start-end-markers switch (ch & 0x1F) { case 0x00: // long variable length ASCII case 0x04: // long variable length unicode _tokenIncomplete = true; return (_currToken = JsonToken.VALUE_STRING); case 0x08: // binary, 7-bit _tokenIncomplete = true; return (_currToken = JsonToken.VALUE_EMBEDDED_OBJECT); case 0x0C: // long shared string case 0x0D: case 0x0E: case 0x0F: if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } return _handleSharedString(((ch & 0x3) << 8) + (_inputBuffer[_inputPtr++] & 0xFF)); case 0x18: // START_ARRAY _parsingContext = _parsingContext.createChildArrayContext(-1, -1); return (_currToken = JsonToken.START_ARRAY); case 0x19: // END_ARRAY if (!_parsingContext.inArray()) { _reportMismatchedEndMarker(']', '}'); } _parsingContext = _parsingContext.getParent(); return (_currToken = JsonToken.END_ARRAY); case 0x1A: // START_OBJECT _parsingContext = _parsingContext.createChildObjectContext(-1, -1); return (_currToken = JsonToken.START_OBJECT); case 0x1B: // not used in this mode; would be END_OBJECT _reportError("Invalid type marker byte 0xFB in value mode (would be END_OBJECT in key mode)"); case 0x1D: // binary, raw _tokenIncomplete = true; return (_currToken = JsonToken.VALUE_EMBEDDED_OBJECT); case 0x1F: // 0xFF, end of content return (_currToken = null); } break; } // If we get this far, type byte is corrupt _reportError("Invalid type marker byte 0x"+Integer.toHexString(ch & 0xFF)+" for expected value token"); return null; } private final JsonToken _handleSharedString(int index) throws IOException, JsonParseException { if (index >= _seenStringValueCount) { _reportInvalidSharedStringValue(index); } _textBuffer.resetWithString(_seenStringValues[index]); return (_currToken = JsonToken.VALUE_STRING); } private final void _addSeenStringValue() throws IOException, JsonParseException { _finishToken(); if (_seenStringValueCount < _seenStringValues.length) { // !!! TODO: actually only store char[], first time around? _seenStringValues[_seenStringValueCount++] = _textBuffer.contentsAsString(); return; } _expandSeenStringValues(); } private final void _expandSeenStringValues() { String[] oldShared = _seenStringValues; int len = oldShared.length; String[] newShared; if (len == 0) { newShared = _smileBufferRecycler.allocSeenStringValuesBuffer(); if (newShared == null) { newShared = new String[SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH]; } } else if (len == SmileConstants.MAX_SHARED_STRING_VALUES) { // too many? Just flush... newShared = oldShared; _seenStringValueCount = 0; // could also clear, but let's not yet bother } else { int newSize = (len == SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH) ? 256 : SmileConstants.MAX_SHARED_STRING_VALUES; newShared = new String[newSize]; System.arraycopy(oldShared, 0, newShared, 0, oldShared.length); } _seenStringValues = newShared; _seenStringValues[_seenStringValueCount++] = _textBuffer.contentsAsString(); } @Override public String getCurrentName() throws IOException, JsonParseException { return _parsingContext.getCurrentName(); } @Override public NumberType getNumberType() throws IOException, JsonParseException { if (_got32BitFloat) { return NumberType.FLOAT; } return super.getNumberType(); } /* /********************************************************** /* Public API, traversal, nextXxxValue/nextFieldName /********************************************************** */ @Override public boolean nextFieldName(SerializableString str) throws IOException, JsonParseException { // Two parsing modes; can only succeed if expecting field name, so handle that first: if (_parsingContext.inObject() && _currToken != JsonToken.FIELD_NAME) { byte[] nameBytes = str.asQuotedUTF8(); final int byteLen = nameBytes.length; // need room for type byte, name bytes, possibly end marker, so: if ((_inputPtr + byteLen + 1) < _inputEnd) { // maybe... int ptr = _inputPtr; int ch = _inputBuffer[ptr++]; _typeByte = ch; main_switch: switch ((ch >> 6) & 3) { case 0: // misc, including end marker switch (ch) { case 0x20: // empty String as name, legal if unusual _currToken = JsonToken.FIELD_NAME; _inputPtr = ptr; _parsingContext.setCurrentName(""); return (byteLen == 0); case 0x30: // long shared case 0x31: case 0x32: case 0x33: { int index = ((ch & 0x3) << 8) + (_inputBuffer[ptr++] & 0xFF); if (index >= _seenNameCount) { _reportInvalidSharedName(index); } String name = _seenNames[index]; _parsingContext.setCurrentName(name); _inputPtr = ptr; _currToken = JsonToken.FIELD_NAME; return (name.equals(str.getValue())); } //case 0x34: // long ASCII/Unicode name; let's not even try... } break; case 1: // short shared, can fully process { int index = (ch & 0x3F); if (index >= _seenNameCount) { _reportInvalidSharedName(index); } _parsingContext.setCurrentName(_seenNames[index]); String name = _seenNames[index]; _parsingContext.setCurrentName(name); _inputPtr = ptr; _currToken = JsonToken.FIELD_NAME; return (name.equals(str.getValue())); } case 2: // short ASCII { int len = 1 + (ch & 0x3f); if (len == byteLen) { int i = 0; for (; i < len; ++i) { if (nameBytes[i] != _inputBuffer[ptr+i]) { break main_switch; } } // yes, does match... _inputPtr = ptr + len; final String name = str.getValue(); if (_seenNames != null) { if (_seenNameCount >= _seenNames.length) { _seenNames = _expandSeenNames(_seenNames); } _seenNames[_seenNameCount++] = name; } _parsingContext.setCurrentName(name); _currToken = JsonToken.FIELD_NAME; return true; } } break; case 3: // short Unicode // all valid, except for 0xFF { int len = (ch & 0x3F); if (len > 0x37) { if (len == 0x3B) { _currToken = JsonToken.END_OBJECT; if (!_parsingContext.inObject()) { _reportMismatchedEndMarker('}', ']'); } _inputPtr = ptr; _parsingContext = _parsingContext.getParent(); return false; } // error, but let's not worry about that here break; } len += 2; // values from 2 to 57... if (len == byteLen) { int i = 0; for (; i < len; ++i) { if (nameBytes[i] != _inputBuffer[ptr+i]) { break main_switch; } } // yes, does match... _inputPtr = ptr + len; final String name = str.getValue(); if (_seenNames != null) { if (_seenNameCount >= _seenNames.length) { _seenNames = _expandSeenNames(_seenNames); } _seenNames[_seenNameCount++] = name; } _parsingContext.setCurrentName(name); _currToken = JsonToken.FIELD_NAME; return true; } } break; } } // otherwise fall back to default processing: JsonToken t = _handleFieldName(); _currToken = t; return (t == JsonToken.FIELD_NAME) && str.getValue().equals(_parsingContext.getCurrentName()); } // otherwise just fall back to default handling; should occur rarely return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName()); } @Override public String nextTextValue() throws IOException, JsonParseException { // can't get text value if expecting name, so if (!_parsingContext.inObject() || _currToken == JsonToken.FIELD_NAME) { if (_tokenIncomplete) { _skipIncomplete(); } int ptr = _inputPtr; if (ptr >= _inputEnd) { if (!loadMore()) { _handleEOF(); close(); _currToken = null; return null; } ptr = _inputPtr; } int ch = _inputBuffer[ptr++]; _tokenInputTotal = _currInputProcessed + _inputPtr; // also: clear any data retained so far _binaryValue = null; _typeByte = ch; switch ((ch >> 5) & 0x7) { case 0: // short shared string value reference if (ch == 0) { // important: this is invalid, don't accept _reportError("Invalid token byte 0x00"); } // _handleSharedString... { --ch; if (ch >= _seenStringValueCount) { _reportInvalidSharedStringValue(ch); } _inputPtr = ptr; String text = _seenStringValues[ch]; _textBuffer.resetWithString(text); _currToken = JsonToken.VALUE_STRING; return text; } case 1: // simple literals, numbers { int typeBits = ch & 0x1F; if (typeBits == 0x00) { _inputPtr = ptr; _textBuffer.resetWithEmpty(); _currToken = JsonToken.VALUE_STRING; return ""; } } break; case 2: // tiny ASCII // fall through case 3: // short ASCII _currToken = JsonToken.VALUE_STRING; _inputPtr = ptr; _decodeShortAsciiValue(1 + (ch & 0x3F)); { // No need to decode, unless we have to keep track of back-references (for shared string values) String text; if (_seenStringValueCount >= 0) { // shared text values enabled if (_seenStringValueCount < _seenStringValues.length) { text = _textBuffer.contentsAsString(); _seenStringValues[_seenStringValueCount++] = text; } else { _expandSeenStringValues(); text = _textBuffer.contentsAsString(); } } else { text = _textBuffer.contentsAsString(); } return text; } case 4: // tiny Unicode // fall through case 5: // short Unicode _currToken = JsonToken.VALUE_STRING; _inputPtr = ptr; _decodeShortUnicodeValue(2 + (ch & 0x3F)); { // No need to decode, unless we have to keep track of back-references (for shared string values) String text; if (_seenStringValueCount >= 0) { // shared text values enabled if (_seenStringValueCount < _seenStringValues.length) { text = _textBuffer.contentsAsString(); _seenStringValues[_seenStringValueCount++] = text; } else { _expandSeenStringValues(); text = _textBuffer.contentsAsString(); } } else { text = _textBuffer.contentsAsString(); } return text; } case 6: // small integers; zigzag encoded break; case 7: // binary/long-text/long-shared/start-end-markers // TODO: support longer strings too? /* switch (ch & 0x1F) { case 0x00: // long variable length ASCII case 0x04: // long variable length unicode _tokenIncomplete = true; return (_currToken = JsonToken.VALUE_STRING); case 0x08: // binary, 7-bit break main; case 0x0C: // long shared string case 0x0D: case 0x0E: case 0x0F: if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } return _handleSharedString(((ch & 0x3) << 8) + (_inputBuffer[_inputPtr++] & 0xFF)); } break; */ break; } } // otherwise fall back to generic handling: return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null; } @Override public int nextIntValue(int defaultValue) throws IOException, JsonParseException { if (nextToken() == JsonToken.VALUE_NUMBER_INT) { return getIntValue(); } return defaultValue; } @Override public long nextLongValue(long defaultValue) throws IOException, JsonParseException { if (nextToken() == JsonToken.VALUE_NUMBER_INT) { return getLongValue(); } return defaultValue; } @Override public Boolean nextBooleanValue() throws IOException, JsonParseException { switch (nextToken()) { case VALUE_TRUE: return Boolean.TRUE; case VALUE_FALSE: return Boolean.FALSE; } return null; } /* /********************************************************** /* Public API, access to token information, text /********************************************************** */ /** * Method for accessing textual representation of the current event; * if no current event (before first call to {@link #nextToken}, or * after encountering end-of-input), returns null. * Method can be called for any event. */ @Override public String getText() throws IOException, JsonParseException { if (_tokenIncomplete) { _tokenIncomplete = false; // Let's inline part of "_finishToken", common case int tb = _typeByte; int type = (tb >> 5) & 0x7; if (type == 2 || type == 3) { // tiny & short ASCII _decodeShortAsciiValue(1 + (tb & 0x3F)); return _textBuffer.contentsAsString(); } if (type == 4 || type == 5) { // tiny & short Unicode // short unicode; note, lengths 2 - 65 (off-by-one compared to ASCII) _decodeShortUnicodeValue(2 + (tb & 0x3F)); return _textBuffer.contentsAsString(); } _finishToken(); } if (_currToken == JsonToken.VALUE_STRING) { return _textBuffer.contentsAsString(); } JsonToken t = _currToken; if (t == null) { // null only before/after document return null; } if (t == JsonToken.FIELD_NAME) { return _parsingContext.getCurrentName(); } if (t.isNumeric()) { // TODO: optimize? return getNumberValue().toString(); } return _currToken.asString(); } @Override public char[] getTextCharacters() throws IOException, JsonParseException { if (_currToken != null) { // null only before/after document if (_tokenIncomplete) { _finishToken(); } switch (_currToken) { case VALUE_STRING: return _textBuffer.getTextBuffer(); case FIELD_NAME: if (!_nameCopied) { String name = _parsingContext.getCurrentName(); int nameLen = name.length(); if (_nameCopyBuffer == null) { _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen); } else if (_nameCopyBuffer.length < nameLen) { _nameCopyBuffer = new char[nameLen]; } name.getChars(0, nameLen, _nameCopyBuffer, 0); _nameCopied = true; } return _nameCopyBuffer; // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: // TODO: optimize return getNumberValue().toString().toCharArray(); default: return _currToken.asCharArray(); } } return null; } @Override public int getTextLength() throws IOException, JsonParseException { if (_currToken != null) { // null only before/after document if (_tokenIncomplete) { _finishToken(); } switch (_currToken) { case VALUE_STRING: return _textBuffer.size(); case FIELD_NAME: return _parsingContext.getCurrentName().length(); // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: // TODO: optimize return getNumberValue().toString().length(); default: return _currToken.asCharArray().length; } } return 0; } @Override public int getTextOffset() throws IOException, JsonParseException { return 0; } /* /********************************************************** /* Public API, access to token information, binary /********************************************************** */ @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { if (_tokenIncomplete) { _finishToken(); } if (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT ) { // Todo, maybe: support base64 for text? _reportError("Current token ("+_currToken+") not VALUE_EMBEDDED_OBJECT, can not access as binary"); } return _binaryValue; } @Override protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException, JsonParseException { // Should never get called, but must be defined for base class _throwInternal(); return null; } /* /********************************************************** /* Internal methods, field name parsing /********************************************************** */ /** * Method that handles initial token type recognition for token * that has to be either FIELD_NAME or END_OBJECT. */ protected final JsonToken _handleFieldName() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int ch = _inputBuffer[_inputPtr++]; // is this needed? _typeByte = ch; switch ((ch >> 6) & 3) { case 0: // misc, including end marker switch (ch) { case 0x20: // empty String as name, legal if unusual _parsingContext.setCurrentName(""); return JsonToken.FIELD_NAME; case 0x30: // long shared case 0x31: case 0x32: case 0x33: { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int index = ((ch & 0x3) << 8) + (_inputBuffer[_inputPtr++] & 0xFF); if (index >= _seenNameCount) { _reportInvalidSharedName(index); } _parsingContext.setCurrentName(_seenNames[index]); } return JsonToken.FIELD_NAME; case 0x34: // long ASCII/Unicode name _handleLongFieldName(); return JsonToken.FIELD_NAME; } break; case 1: // short shared, can fully process { int index = (ch & 0x3F); if (index >= _seenNameCount) { _reportInvalidSharedName(index); } _parsingContext.setCurrentName(_seenNames[index]); } return JsonToken.FIELD_NAME; case 2: // short ASCII { int len = 1 + (ch & 0x3f); String name; Name n = _findDecodedFromSymbols(len); if (n != null) { name = n.getName(); _inputPtr += len; } else { name = _decodeShortAsciiName(len); name = _addDecodedToSymbols(len, name); } if (_seenNames != null) { if (_seenNameCount >= _seenNames.length) { _seenNames = _expandSeenNames(_seenNames); } _seenNames[_seenNameCount++] = name; } _parsingContext.setCurrentName(name); } return JsonToken.FIELD_NAME; case 3: // short Unicode // all valid, except for 0xFF ch &= 0x3F; { if (ch > 0x37) { if (ch == 0x3B) { if (!_parsingContext.inObject()) { _reportMismatchedEndMarker('}', ']'); } _parsingContext = _parsingContext.getParent(); return JsonToken.END_OBJECT; } } else { final int len = ch + 2; // values from 2 to 57... String name; Name n = _findDecodedFromSymbols(len); if (n != null) { name = n.getName(); _inputPtr += len; } else { name = _decodeShortUnicodeName(len); name = _addDecodedToSymbols(len, name); } if (_seenNames != null) { if (_seenNameCount >= _seenNames.length) { _seenNames = _expandSeenNames(_seenNames); } _seenNames[_seenNameCount++] = name; } _parsingContext.setCurrentName(name); return JsonToken.FIELD_NAME; } } break; } // Other byte values are illegal _reportError("Invalid type marker byte 0x"+Integer.toHexString(_typeByte)+" for expected field name (or END_OBJECT marker)"); return null; } /** * Method called to try to expand shared name area to fit one more potentially * shared String. If area is already at its biggest size, will just clear * the area (by setting next-offset to 0) */ private final String[] _expandSeenNames(String[] oldShared) { int len = oldShared.length; String[] newShared; if (len == 0) { newShared = _smileBufferRecycler.allocSeenNamesBuffer(); if (newShared == null) { newShared = new String[SmileBufferRecycler.DEFAULT_NAME_BUFFER_LENGTH]; } } else if (len == SmileConstants.MAX_SHARED_NAMES) { // too many? Just flush... newShared = oldShared; _seenNameCount = 0; // could also clear, but let's not yet bother } else { int newSize = (len == SmileBufferRecycler.DEFAULT_STRING_VALUE_BUFFER_LENGTH) ? 256 : SmileConstants.MAX_SHARED_NAMES; newShared = new String[newSize]; System.arraycopy(oldShared, 0, newShared, 0, oldShared.length); } return newShared; } private final String _addDecodedToSymbols(int len, String name) { if (len < 5) { return _symbols.addName(name, _quad1, 0).getName(); } if (len < 9) { return _symbols.addName(name, _quad1, _quad2).getName(); } int qlen = (len + 3) >> 2; return _symbols.addName(name, _quadBuffer, qlen).getName(); } private final String _decodeShortAsciiName(int len) throws IOException, JsonParseException { // note: caller ensures we have enough bytes available char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int outPtr = 0; final byte[] inBuf = _inputBuffer; int inPtr = _inputPtr; // loop unrolling seems to help here: for (int inEnd = inPtr + len - 3; inPtr < inEnd; ) { outBuf[outPtr++] = (char) inBuf[inPtr++]; outBuf[outPtr++] = (char) inBuf[inPtr++]; outBuf[outPtr++] = (char) inBuf[inPtr++]; outBuf[outPtr++] = (char) inBuf[inPtr++]; } int left = (len & 3); if (left > 0) { outBuf[outPtr++] = (char) inBuf[inPtr++]; if (left > 1) { outBuf[outPtr++] = (char) inBuf[inPtr++]; if (left > 2) { outBuf[outPtr++] = (char) inBuf[inPtr++]; } } } _inputPtr = inPtr; _textBuffer.setCurrentLength(len); return _textBuffer.contentsAsString(); } /** * Helper method used to decode short Unicode string, length for which actual * length (in bytes) is known * * @param len Length between 1 and 64 */ private final String _decodeShortUnicodeName(int len) throws IOException, JsonParseException { // note: caller ensures we have enough bytes available int outPtr = 0; char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int inPtr = _inputPtr; _inputPtr += len; final int[] codes = SmileConstants.sUtf8UnitLengths; final byte[] inBuf = _inputBuffer; for (int end = inPtr + len; inPtr < end; ) { int i = inBuf[inPtr++] & 0xFF; int code = codes[i]; if (code != 0) { // trickiest one, need surrogate handling switch (code) { case 1: i = ((i & 0x1F) << 6) | (inBuf[inPtr++] & 0x3F); break; case 2: i = ((i & 0x0F) << 12) | ((inBuf[inPtr++] & 0x3F) << 6) | (inBuf[inPtr++] & 0x3F); break; case 3: i = ((i & 0x07) << 18) | ((inBuf[inPtr++] & 0x3F) << 12) | ((inBuf[inPtr++] & 0x3F) << 6) | (inBuf[inPtr++] & 0x3F); // note: this is the codepoint value; need to split, too i -= 0x10000; outBuf[outPtr++] = (char) (0xD800 | (i >> 10)); i = 0xDC00 | (i & 0x3FF); break; default: // invalid _reportError("Invalid byte "+Integer.toHexString(i)+" in short Unicode text block"); } } outBuf[outPtr++] = (char) i; } _textBuffer.setCurrentLength(outPtr); return _textBuffer.contentsAsString(); } // note: slightly edited copy of UTF8StreamParser.addName() private final Name _decodeLongUnicodeName(int[] quads, int byteLen, int quadLen) throws IOException, JsonParseException { int lastQuadBytes = byteLen & 3; // Ok: must decode UTF-8 chars. No other validation SHOULD be needed (except bounds checks?) /* Note: last quad is not correctly aligned (leading zero bytes instead * need to shift a bit, instead of trailing). Only need to shift it * for UTF-8 decoding; need revert for storage (since key will not * be aligned, to optimize lookup speed) */ int lastQuad; if (lastQuadBytes < 4) { lastQuad = quads[quadLen-1]; // 8/16/24 bit left shift quads[quadLen-1] = (lastQuad << ((4 - lastQuadBytes) << 3)); } else { lastQuad = 0; } char[] cbuf = _textBuffer.emptyAndGetCurrentSegment(); int cix = 0; for (int ix = 0; ix < byteLen; ) { int ch = quads[ix >> 2]; // current quad, need to shift+mask int byteIx = (ix & 3); ch = (ch >> ((3 - byteIx) << 3)) & 0xFF; ++ix; if (ch > 127) { // multi-byte int needed; if ((ch & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) ch &= 0x1F; needed = 1; } else if ((ch & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) ch &= 0x0F; needed = 2; } else if ((ch & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all... ch &= 0x07; needed = 3; } else { // 5- and 6-byte chars not valid chars _reportInvalidInitial(ch); needed = ch = 1; // never really gets this far } if ((ix + needed) > byteLen) { _reportInvalidEOF(" in long field name"); } // Ok, always need at least one more: int ch2 = quads[ix >> 2]; // current quad, need to shift+mask byteIx = (ix & 3); ch2 = (ch2 >> ((3 - byteIx) << 3)); ++ix; if ((ch2 & 0xC0) != 0x080) { _reportInvalidOther(ch2); } ch = (ch << 6) | (ch2 & 0x3F); if (needed > 1) { ch2 = quads[ix >> 2]; byteIx = (ix & 3); ch2 = (ch2 >> ((3 - byteIx) << 3)); ++ix; if ((ch2 & 0xC0) != 0x080) { _reportInvalidOther(ch2); } ch = (ch << 6) | (ch2 & 0x3F); if (needed > 2) { // 4 bytes? (need surrogates on output) ch2 = quads[ix >> 2]; byteIx = (ix & 3); ch2 = (ch2 >> ((3 - byteIx) << 3)); ++ix; if ((ch2 & 0xC0) != 0x080) { _reportInvalidOther(ch2 & 0xFF); } ch = (ch << 6) | (ch2 & 0x3F); } } if (needed > 2) { // surrogate pair? once again, let's output one here, one later on ch -= 0x10000; // to normalize it starting with 0x0 if (cix >= cbuf.length) { cbuf = _textBuffer.expandCurrentSegment(); } cbuf[cix++] = (char) (0xD800 + (ch >> 10)); ch = 0xDC00 | (ch & 0x03FF); } } if (cix >= cbuf.length) { cbuf = _textBuffer.expandCurrentSegment(); } cbuf[cix++] = (char) ch; } // Ok. Now we have the character array, and can construct the String String baseName = new String(cbuf, 0, cix); // And finally, un-align if necessary if (lastQuadBytes < 4) { quads[quadLen-1] = lastQuad; } return _symbols.addName(baseName, quads, quadLen); } private final void _handleLongFieldName() throws IOException, JsonParseException { // First: gather quads we need, looking for end marker final byte[] inBuf = _inputBuffer; int quads = 0; int bytes = 0; int q = 0; while (true) { byte b = inBuf[_inputPtr++]; if (BYTE_MARKER_END_OF_STRING == b) { bytes = 0; break; } q = ((int) b) & 0xFF; b = inBuf[_inputPtr++]; if (BYTE_MARKER_END_OF_STRING == b) { bytes = 1; break; } q = (q << 8) | (b & 0xFF); b = inBuf[_inputPtr++]; if (BYTE_MARKER_END_OF_STRING == b) { bytes = 2; break; } q = (q << 8) | (b & 0xFF); b = inBuf[_inputPtr++]; if (BYTE_MARKER_END_OF_STRING == b) { bytes = 3; break; } q = (q << 8) | (b & 0xFF); if (quads >= _quadBuffer.length) { _quadBuffer = _growArrayTo(_quadBuffer, _quadBuffer.length + 256); // grow by 1k } _quadBuffer[quads++] = q; } // and if we have more bytes, append those too int byteLen = (quads << 2); if (bytes > 0) { if (quads >= _quadBuffer.length) { _quadBuffer = _growArrayTo(_quadBuffer, _quadBuffer.length + 256); } _quadBuffer[quads++] = q; byteLen += bytes; } // Know this name already? String name; Name n = _symbols.findName(_quadBuffer, quads); if (n != null) { name = n.getName(); } else { name = _decodeLongUnicodeName(_quadBuffer, byteLen, quads).getName(); } if (_seenNames != null) { if (_seenNameCount >= _seenNames.length) { _seenNames = _expandSeenNames(_seenNames); } _seenNames[_seenNameCount++] = name; } _parsingContext.setCurrentName(name); } /** * Helper method for trying to find specified encoded UTF-8 byte sequence * from symbol table; if successful avoids actual decoding to String */ private final Name _findDecodedFromSymbols(int len) throws IOException, JsonParseException { if ((_inputEnd - _inputPtr) < len) { _loadToHaveAtLeast(len); } // First: maybe we already have this name decoded? if (len < 5) { int inPtr = _inputPtr; final byte[] inBuf = _inputBuffer; int q = inBuf[inPtr] & 0xFF; if (--len > 0) { q = (q << 8) + (inBuf[++inPtr] & 0xFF); if (--len > 0) { q = (q << 8) + (inBuf[++inPtr] & 0xFF); if (--len > 0) { q = (q << 8) + (inBuf[++inPtr] & 0xFF); } } } _quad1 = q; return _symbols.findName(q); } if (len < 9) { int inPtr = _inputPtr; final byte[] inBuf = _inputBuffer; // First quadbyte is easy int q1 = (inBuf[inPtr] & 0xFF) << 8; q1 += (inBuf[++inPtr] & 0xFF); q1 <<= 8; q1 += (inBuf[++inPtr] & 0xFF); q1 <<= 8; q1 += (inBuf[++inPtr] & 0xFF); int q2 = (inBuf[++inPtr] & 0xFF); len -= 5; if (len > 0) { q2 = (q2 << 8) + (inBuf[++inPtr] & 0xFF); if (--len > 0) { q2 = (q2 << 8) + (inBuf[++inPtr] & 0xFF); if (--len > 0) { q2 = (q2 << 8) + (inBuf[++inPtr] & 0xFF); } } } _quad1 = q1; _quad2 = q2; return _symbols.findName(q1, q2); } return _findDecodedMedium(len); } /** * Method for locating names longer than 8 bytes (in UTF-8) */ private final Name _findDecodedMedium(int len) throws IOException, JsonParseException { // first, need enough buffer to store bytes as ints: { int bufLen = (len + 3) >> 2; if (bufLen > _quadBuffer.length) { _quadBuffer = _growArrayTo(_quadBuffer, bufLen); } } // then decode, full quads first int offset = 0; int inPtr = _inputPtr; final byte[] inBuf = _inputBuffer; do { int q = (inBuf[inPtr++] & 0xFF) << 8; q |= inBuf[inPtr++] & 0xFF; q <<= 8; q |= inBuf[inPtr++] & 0xFF; q <<= 8; q |= inBuf[inPtr++] & 0xFF; _quadBuffer[offset++] = q; } while ((len -= 4) > 3); // and then leftovers if (len > 0) { int q = inBuf[inPtr] & 0xFF; if (--len > 0) { q = (q << 8) + (inBuf[++inPtr] & 0xFF); if (--len > 0) { q = (q << 8) + (inBuf[++inPtr] & 0xFF); } } _quadBuffer[offset++] = q; } return _symbols.findName(_quadBuffer, offset); } private static int[] _growArrayTo(int[] arr, int minSize) { int[] newArray = new int[minSize + 4]; if (arr != null) { // !!! TODO: JDK 1.6, Arrays.copyOf System.arraycopy(arr, 0, newArray, 0, arr.length); } return newArray; } /* /********************************************************** /* Internal methods, secondary parsing /********************************************************** */ @Override protected void _parseNumericValue(int expType) throws IOException, JsonParseException { if (_tokenIncomplete) { int tb = _typeByte; // ensure we got a numeric type with value that is lazily parsed if (((tb >> 5) & 0x7) != 1) { _reportError("Current token ("+_currToken+") not numeric, can not use numeric value accessors"); } _tokenIncomplete = false; _finishNumberToken(tb); } } /** * Method called to finish parsing of a token so that token contents * are retriable */ protected void _finishToken() throws IOException, JsonParseException { _tokenIncomplete = false; int tb = _typeByte; int type = ((tb >> 5) & 0x7); if (type == 1) { // simple literals, numbers _finishNumberToken(tb); return; } if (type <= 3) { // tiny & short ASCII _decodeShortAsciiValue(1 + (tb & 0x3F)); return; } if (type <= 5) { // tiny & short Unicode // short unicode; note, lengths 2 - 65 (off-by-one compared to ASCII) _decodeShortUnicodeValue(2 + (tb & 0x3F)); return; } if (type == 7) { tb &= 0x1F; // next 3 bytes define subtype switch (tb >> 2) { case 0: // long variable length ASCII _decodeLongAscii(); return; case 1: // long variable length unicode _decodeLongUnicode(); return; case 2: // binary, 7-bit _binaryValue = _read7BitBinaryWithLength(); return; case 7: // binary, raw _finishRawBinary(); return; } } // sanity check _throwInternal(); } protected final void _finishNumberToken(int tb) throws IOException, JsonParseException { tb &= 0x1F; int type = (tb >> 2); if (type == 1) { // VInt (zigzag) or BigDecimal int subtype = tb & 0x03; if (subtype == 0) { // (v)int _finishInt(); } else if (subtype == 1) { // (v)long _finishLong(); } else if (subtype == 2) { _finishBigInteger(); } else { _throwInternal(); } return; } if (type == 2) { // other numbers switch (tb & 0x03) { case 0: // float _finishFloat(); return; case 1: // double _finishDouble(); return; case 2: // big-decimal _finishBigDecimal(); return; } } _throwInternal(); } /* /********************************************************** /* Internal methods, secondary Number parsing /********************************************************** */ private final void _finishInt() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int value = _inputBuffer[_inputPtr++]; int i; if (value < 0) { // 6 bits value &= 0x3F; } else { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = _inputBuffer[_inputPtr++]; if (i >= 0) { // 13 bits value = (value << 7) + i; if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = _inputBuffer[_inputPtr++]; if (i >= 0) { value = (value << 7) + i; if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = _inputBuffer[_inputPtr++]; if (i >= 0) { value = (value << 7) + i; // and then we must get negative if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = _inputBuffer[_inputPtr++]; if (i >= 0) { _reportError("Corrupt input; 32-bit VInt extends beyond 5 data bytes"); } } } } value = (value << 6) + (i & 0x3F); } _numberInt = SmileUtil.zigzagDecode(value); _numTypesValid = NR_INT; } private final void _finishLong() throws IOException, JsonParseException { // Ok, first, will always get 4 full data bytes first; 1 was already passed long l = (long) _fourBytesToInt(); // and loop for the rest while (true) { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int value = _inputBuffer[_inputPtr++]; if (value < 0) { l = (l << 6) + (value & 0x3F); _numberLong = SmileUtil.zigzagDecode(l); _numTypesValid = NR_LONG; return; } l = (l << 7) + value; } } private final void _finishBigInteger() throws IOException, JsonParseException { byte[] raw = _read7BitBinaryWithLength(); _numberBigInt = new BigInteger(raw); _numTypesValid = NR_BIGINT; } private final void _finishFloat() throws IOException, JsonParseException { // just need 5 bytes to get int32 first; all are unsigned int i = _fourBytesToInt(); if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = (i << 7) + _inputBuffer[_inputPtr++]; float f = Float.intBitsToFloat(i); _numberDouble = (double) f; _numTypesValid = NR_DOUBLE; } private final void _finishDouble() throws IOException, JsonParseException { // ok; let's take two sets of 4 bytes (each is int) long hi = _fourBytesToInt(); long value = (hi << 28) + (long) _fourBytesToInt(); // and then remaining 2 bytes if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } value = (value << 7) + _inputBuffer[_inputPtr++]; if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } value = (value << 7) + _inputBuffer[_inputPtr++]; _numberDouble = Double.longBitsToDouble(value); _numTypesValid = NR_DOUBLE; } private final int _fourBytesToInt() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int i = _inputBuffer[_inputPtr++]; // first 7 bits if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = (i << 7) + _inputBuffer[_inputPtr++]; // 14 bits if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = (i << 7) + _inputBuffer[_inputPtr++]; // 21 if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } return (i << 7) + _inputBuffer[_inputPtr++]; } private final void _finishBigDecimal() throws IOException, JsonParseException { int scale = SmileUtil.zigzagDecode(_readUnsignedVInt()); byte[] raw = _read7BitBinaryWithLength(); _numberBigDecimal = new BigDecimal(new BigInteger(raw), scale); _numTypesValid = NR_BIGDECIMAL; } private final int _readUnsignedVInt() throws IOException, JsonParseException { int value = 0; while (true) { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int i = _inputBuffer[_inputPtr++]; if (i < 0) { // last byte value = (value << 6) + (i & 0x3F); return value; } value = (value << 7) + i; } } private final byte[] _read7BitBinaryWithLength() throws IOException, JsonParseException { int byteLen = _readUnsignedVInt(); byte[] result = new byte[byteLen]; int ptr = 0; int lastOkPtr = byteLen - 7; // first, read all 7-by-8 byte chunks while (ptr <= lastOkPtr) { if ((_inputEnd - _inputPtr) < 8) { _loadToHaveAtLeast(8); } int i1 = (_inputBuffer[_inputPtr++] << 25) + (_inputBuffer[_inputPtr++] << 18) + (_inputBuffer[_inputPtr++] << 11) + (_inputBuffer[_inputPtr++] << 4); int x = _inputBuffer[_inputPtr++]; i1 += x >> 3; int i2 = ((x & 0x7) << 21) + (_inputBuffer[_inputPtr++] << 14) + (_inputBuffer[_inputPtr++] << 7) + _inputBuffer[_inputPtr++]; // Ok: got our 7 bytes, just need to split, copy result[ptr++] = (byte)(i1 >> 24); result[ptr++] = (byte)(i1 >> 16); result[ptr++] = (byte)(i1 >> 8); result[ptr++] = (byte)i1; result[ptr++] = (byte)(i2 >> 16); result[ptr++] = (byte)(i2 >> 8); result[ptr++] = (byte)i2; } // and then leftovers: n+1 bytes to decode n bytes int toDecode = (result.length - ptr); if (toDecode > 0) { if ((_inputEnd - _inputPtr) < (toDecode+1)) { _loadToHaveAtLeast(toDecode+1); } int value = _inputBuffer[_inputPtr++]; for (int i = 1; i < toDecode; ++i) { value = (value << 7) + _inputBuffer[_inputPtr++]; result[ptr++] = (byte) (value >> (7 - i)); } // last byte is different, has remaining 1 - 6 bits, right-aligned value <<= toDecode; result[ptr] = (byte) (value + _inputBuffer[_inputPtr++]); } return result; } /* /********************************************************** /* Internal methods, secondary String parsing /********************************************************** */ protected final void _decodeShortAsciiValue(int len) throws IOException, JsonParseException { if ((_inputEnd - _inputPtr) < len) { _loadToHaveAtLeast(len); } // Note: we count on fact that buffer must have at least 'len' (<= 64) empty char slots final char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int outPtr = 0; final byte[] inBuf = _inputBuffer; int inPtr = _inputPtr; // loop unrolling SHOULD be faster (as with _decodeShortAsciiName), but somehow // is NOT; as per testing, benchmarking... very weird. /* for (int inEnd = inPtr + len - 3; inPtr < inEnd; ) { outBuf[outPtr++] = (char) inBuf[inPtr++]; outBuf[outPtr++] = (char) inBuf[inPtr++]; outBuf[outPtr++] = (char) inBuf[inPtr++]; outBuf[outPtr++] = (char) inBuf[inPtr++]; } int left = (len & 3); if (left > 0) { outBuf[outPtr++] = (char) inBuf[inPtr++]; if (left > 1) { outBuf[outPtr++] = (char) inBuf[inPtr++]; if (left > 2) { outBuf[outPtr++] = (char) inBuf[inPtr++]; } } } */ // meaning: regular tight loop is no slower, typically faster here: for (final int end = inPtr + len; inPtr < end; ++inPtr) { outBuf[outPtr++] = (char) inBuf[inPtr]; } _inputPtr = inPtr; _textBuffer.setCurrentLength(len); } protected final void _decodeShortUnicodeValue(int len) throws IOException, JsonParseException { if ((_inputEnd - _inputPtr) < len) { _loadToHaveAtLeast(len); } int outPtr = 0; char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int inPtr = _inputPtr; _inputPtr += len; final int[] codes = SmileConstants.sUtf8UnitLengths; final byte[] inputBuf = _inputBuffer; for (int end = inPtr + len; inPtr < end; ) { int i = inputBuf[inPtr++] & 0xFF; int code = codes[i]; if (code != 0) { // trickiest one, need surrogate handling switch (code) { case 1: i = ((i & 0x1F) << 6) | (inputBuf[inPtr++] & 0x3F); break; case 2: i = ((i & 0x0F) << 12) | ((inputBuf[inPtr++] & 0x3F) << 6) | (inputBuf[inPtr++] & 0x3F); break; case 3: i = ((i & 0x07) << 18) | ((inputBuf[inPtr++] & 0x3F) << 12) | ((inputBuf[inPtr++] & 0x3F) << 6) | (inputBuf[inPtr++] & 0x3F); // note: this is the codepoint value; need to split, too i -= 0x10000; outBuf[outPtr++] = (char) (0xD800 | (i >> 10)); i = 0xDC00 | (i & 0x3FF); break; default: // invalid _reportError("Invalid byte "+Integer.toHexString(i)+" in short Unicode text block"); } } outBuf[outPtr++] = (char) i; } _textBuffer.setCurrentLength(outPtr); } private final void _decodeLongAscii() throws IOException, JsonParseException { int outPtr = 0; char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); main_loop: while (true) { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int inPtr = _inputPtr; int left = _inputEnd - inPtr; if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } left = Math.min(left, outBuf.length - outPtr); do { byte b = _inputBuffer[inPtr++]; if (b == SmileConstants.BYTE_MARKER_END_OF_STRING) { _inputPtr = inPtr; break main_loop; } outBuf[outPtr++] = (char) b; } while (--left > 0); _inputPtr = inPtr; } _textBuffer.setCurrentLength(outPtr); } private final void _decodeLongUnicode() throws IOException, JsonParseException { int outPtr = 0; char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); final int[] codes = SmileConstants.sUtf8UnitLengths; int c; final byte[] inputBuffer = _inputBuffer; main_loop: while (true) { // First the tight ASCII loop: ascii_loop: while (true) { int ptr = _inputPtr; if (ptr >= _inputEnd) { loadMoreGuaranteed(); ptr = _inputPtr; } if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } int max = _inputEnd; { int max2 = ptr + (outBuf.length - outPtr); if (max2 < max) { max = max2; } } while (ptr < max) { c = (int) inputBuffer[ptr++] & 0xFF; if (codes[c] != 0) { _inputPtr = ptr; break ascii_loop; } outBuf[outPtr++] = (char) c; } _inputPtr = ptr; } // Ok: end marker, escape or multi-byte? if (c == SmileConstants.INT_MARKER_END_OF_STRING) { break main_loop; } switch (codes[c]) { case 1: // 2-byte UTF c = _decodeUtf8_2(c); break; case 2: // 3-byte UTF if ((_inputEnd - _inputPtr) >= 2) { c = _decodeUtf8_3fast(c); } else { c = _decodeUtf8_3(c); } break; case 4: // 4-byte UTF c = _decodeUtf8_4(c); // Let's add first part right away: outBuf[outPtr++] = (char) (0xD800 | (c >> 10)); if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } c = 0xDC00 | (c & 0x3FF); // And let the other char output down below break; default: // Is this good enough error message? _reportInvalidChar(c); } // Need more room? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } // Ok, let's add char to output: outBuf[outPtr++] = (char) c; } _textBuffer.setCurrentLength(outPtr); } private final void _finishRawBinary() throws IOException, JsonParseException { int byteLen = _readUnsignedVInt(); _binaryValue = new byte[byteLen]; if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int ptr = 0; while (true) { int toAdd = Math.min(byteLen, _inputEnd - _inputPtr); System.arraycopy(_inputBuffer, _inputPtr, _binaryValue, ptr, toAdd); _inputPtr += toAdd; ptr += toAdd; byteLen -= toAdd; if (byteLen <= 0) { return; } loadMoreGuaranteed(); } } /* /********************************************************** /* Internal methods, skipping /********************************************************** */ /** * Method called to skip remainders of an incomplete token, when * contents themselves will not be needed any more */ protected void _skipIncomplete() throws IOException, JsonParseException { _tokenIncomplete = false; int tb = _typeByte; switch ((tb >> 5) & 0x7) { case 1: // simple literals, numbers tb &= 0x1F; // next 3 bytes define subtype switch (tb >> 2) { case 1: // VInt (zigzag) // easy, just skip until we see sign bit... (should we try to limit damage?) switch (tb & 0x3) { case 1: // vlong _skipBytes(4); // min 5 bytes // fall through case 0: // vint while (true) { final int end = _inputEnd; final byte[] buf = _inputBuffer; while (_inputPtr < end) { if (buf[_inputPtr++] < 0) { return; } } loadMoreGuaranteed(); } case 2: // big-int // just has binary data _skip7BitBinary(); return; } break; case 2: // other numbers switch (tb & 0x3) { case 0: // float _skipBytes(5); return; case 1: // double _skipBytes(10); return; case 2: // big-decimal // first, skip scale _readUnsignedVInt(); // then length-prefixed binary serialization _skip7BitBinary(); return; } break; } break; case 2: // tiny ASCII // fall through case 3: // short ASCII _skipBytes(1 + (tb & 0x3F)); return; case 4: // tiny unicode // fall through case 5: // short unicode _skipBytes(2 + (tb & 0x3F)); return; case 7: tb &= 0x1F; // next 3 bytes define subtype switch (tb >> 2) { case 0: // long variable length ASCII case 1: // long variable length unicode /* Doesn't matter which one, just need to find the end marker * (note: can potentially skip invalid UTF-8 too) */ while (true) { final int end = _inputEnd; final byte[] buf = _inputBuffer; while (_inputPtr < end) { if (buf[_inputPtr++] == BYTE_MARKER_END_OF_STRING) { return; } } loadMoreGuaranteed(); } // never gets here case 2: // binary, 7-bit _skip7BitBinary(); return; case 7: // binary, raw _skipBytes(_readUnsignedVInt()); return; } } _throwInternal(); } protected void _skipBytes(int len) throws IOException, JsonParseException { while (true) { int toAdd = Math.min(len, _inputEnd - _inputPtr); _inputPtr += toAdd; len -= toAdd; if (len <= 0) { return; } loadMoreGuaranteed(); } } /** * Helper method for skipping length-prefixed binary data * section */ protected void _skip7BitBinary() throws IOException, JsonParseException { int origBytes = _readUnsignedVInt(); // Ok; 8 encoded bytes for 7 payload bytes first int chunks = origBytes / 7; int encBytes = chunks * 8; // and for last 0 - 6 bytes, last+1 (except none if no leftovers) origBytes -= 7 * chunks; if (origBytes > 0) { encBytes += 1 + origBytes; } _skipBytes(encBytes); } /* /********************************************************** /* Internal methods, UTF8 decoding /********************************************************** */ private final int _decodeUtf8_2(int c) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } return ((c & 0x1F) << 6) | (d & 0x3F); } private final int _decodeUtf8_3(int c1) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } c1 &= 0x0F; int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } int c = (c1 << 6) | (d & 0x3F); if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = (c << 6) | (d & 0x3F); return c; } private final int _decodeUtf8_3fast(int c1) throws IOException, JsonParseException { c1 &= 0x0F; int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } int c = (c1 << 6) | (d & 0x3F); d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = (c << 6) | (d & 0x3F); return c; } /** * @return Character value minus 0x10000; this so that caller * can readily expand it to actual surrogates */ private final int _decodeUtf8_4(int c) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = ((c & 0x07) << 6) | (d & 0x3F); if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = (c << 6) | (d & 0x3F); if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } /* note: won't change it to negative here, since caller * already knows it'll need a surrogate */ return ((c << 6) | (d & 0x3F)) - 0x10000; } /* /********************************************************** /* Internal methods, error reporting /********************************************************** */ protected void _reportInvalidSharedName(int index) throws IOException { if (_seenNames == null) { _reportError("Encountered shared name reference, even though document header explicitly declared no shared name references are included"); } _reportError("Invalid shared name reference "+index+"; only got "+_seenNameCount+" names in buffer (invalid content)"); } protected void _reportInvalidSharedStringValue(int index) throws IOException { if (_seenStringValues == null) { _reportError("Encountered shared text value reference, even though document header did not declared shared text value references may be included"); } _reportError("Invalid shared text value reference "+index+"; only got "+_seenStringValueCount+" names in buffer (invalid content)"); } protected void _reportInvalidChar(int c) throws JsonParseException { // Either invalid WS or illegal UTF-8 start char if (c < ' ') { _throwInvalidSpace(c); } _reportInvalidInitial(c); } protected void _reportInvalidInitial(int mask) throws JsonParseException { _reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask)); } protected void _reportInvalidOther(int mask) throws JsonParseException { _reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask)); } protected void _reportInvalidOther(int mask, int ptr) throws JsonParseException { _inputPtr = ptr; _reportInvalidOther(mask); } } jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/SmileParserBootstrapper.java0000644000175000017500000002253411655120726032067 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; import java.io.*; import org.codehaus.jackson.JsonLocation; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.ObjectCodec; import org.codehaus.jackson.format.InputAccessor; import org.codehaus.jackson.format.MatchStrength; import org.codehaus.jackson.io.IOContext; import org.codehaus.jackson.sym.BytesToNameCanonicalizer; import static org.codehaus.jackson.smile.SmileConstants.*; /** * Simple bootstrapper version used with Smile format parser. */ public class SmileParserBootstrapper { /* /********************************************************** /* Configuration /********************************************************** */ final IOContext _context; final InputStream _in; /* /********************************************************** /* Input buffering /********************************************************** */ final byte[] _inputBuffer; private int _inputPtr; private int _inputEnd; /** * Flag that indicates whether buffer above is to be recycled * after being used or not. */ private final boolean _bufferRecyclable; /* /********************************************************** /* Input location /********************************************************** */ /** * Current number of input units (bytes or chars) that were processed in * previous blocks, * before contents of current input buffer. *

* Note: includes possible BOMs, if those were part of the input. */ protected int _inputProcessed; /* /********************************************************** /* Data gathered /********************************************************** */ /* /********************************************************** /* Life-cycle /********************************************************** */ public SmileParserBootstrapper(IOContext ctxt, InputStream in) { _context = ctxt; _in = in; _inputBuffer = ctxt.allocReadIOBuffer(); _inputEnd = _inputPtr = 0; _inputProcessed = 0; _bufferRecyclable = true; } public SmileParserBootstrapper(IOContext ctxt, byte[] inputBuffer, int inputStart, int inputLen) { _context = ctxt; _in = null; _inputBuffer = inputBuffer; _inputPtr = inputStart; _inputEnd = (inputStart + inputLen); // Need to offset this for correct location info _inputProcessed = -inputStart; _bufferRecyclable = false; } public SmileParser constructParser(int generalParserFeatures, int smileFeatures, ObjectCodec codec, BytesToNameCanonicalizer rootByteSymbols) throws IOException, JsonParseException { boolean intern = JsonParser.Feature.INTERN_FIELD_NAMES.enabledIn(generalParserFeatures); BytesToNameCanonicalizer can = rootByteSymbols.makeChild(true, intern); // We just need a single byte, really, to know if it starts with header ensureLoaded(1); SmileParser p = new SmileParser(_context, generalParserFeatures, smileFeatures, codec, can, _in, _inputBuffer, _inputPtr, _inputEnd, _bufferRecyclable); boolean hadSig = false; if (_inputPtr < _inputEnd) { // only false for empty doc if (_inputBuffer[_inputPtr] == SmileConstants.HEADER_BYTE_1) { // need to ensure it gets properly handled so caller won't see the signature hadSig = p.handleSignature(true, true); } } if (!hadSig && (smileFeatures & SmileParser.Feature.REQUIRE_HEADER.getMask()) != 0) { // Ok, first, let's see if it looks like plain JSON... String msg; byte firstByte = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr] : 0; if (firstByte == '{' || firstByte == '[') { msg = "Input does not start with Smile format header (first byte = 0x" +Integer.toHexString(firstByte & 0xFF)+") -- rather, it starts with '"+((char) firstByte) +"' (plain JSON input?) -- can not parse"; } else { msg = "Input does not start with Smile format header (first byte = 0x" +Integer.toHexString(firstByte & 0xFF)+") and parser has REQUIRE_HEADER enabled: can not parse"; } throw new JsonParseException(msg, JsonLocation.NA); } return p; } /* /********************************************************** /* Encoding detection for data format auto-detection /********************************************************** */ /** * Helper * * @since 1.8 */ public static MatchStrength hasSmileFormat(InputAccessor acc) throws IOException { // Ok: ideally we start with the header -- if so, we are golden if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } // We always need at least two bytes to determine, so byte b1 = acc.nextByte(); if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } byte b2 = acc.nextByte(); // First: do we see 3 "magic bytes"? If so, we are golden if (b1 == SmileConstants.HEADER_BYTE_1) { // yeah, looks like marker if (b2 != SmileConstants.HEADER_BYTE_2) { return MatchStrength.NO_MATCH; } if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } return (acc.nextByte() == SmileConstants.HEADER_BYTE_3) ? MatchStrength.FULL_MATCH : MatchStrength.NO_MATCH; } // Otherwise: ideally either Object or Array: if (b1 == SmileConstants.TOKEN_LITERAL_START_OBJECT) { /* Object is bit easier, because now we need to get new name; i.e. can * rule out name back-refs */ if (b2 == SmileConstants.TOKEN_KEY_LONG_STRING) { return MatchStrength.SOLID_MATCH; } int ch = (int) b2 & 0xFF; if (ch >= 0x80 && ch < 0xF8) { return MatchStrength.SOLID_MATCH; } return MatchStrength.NO_MATCH; } // Array bit trickier if (b1 == SmileConstants.TOKEN_LITERAL_START_ARRAY) { if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } /* For arrays, we will actually accept much wider range of values (including * things that could otherwise collide) */ if (likelySmileValue(b2) || possibleSmileValue(b2, true)) { return MatchStrength.SOLID_MATCH; } return MatchStrength.NO_MATCH; } // Scalar values are pretty weak, albeit possible; require more certain match, consider it weak: if (likelySmileValue(b1) || possibleSmileValue(b2, false)) { return MatchStrength.SOLID_MATCH; } return MatchStrength.NO_MATCH; } private static boolean likelySmileValue(byte b) { int ch = (int) b & 0xFF; if (ch >= 0xE0) { // good range for known values switch (ch) { case TOKEN_MISC_LONG_TEXT_ASCII: // 0xE0 case TOKEN_MISC_LONG_TEXT_UNICODE: // 0xE4 case TOKEN_MISC_BINARY_7BIT: // 0xE8 case TOKEN_LITERAL_START_ARRAY: // 0xF8 case TOKEN_LITERAL_START_OBJECT: // 0xFA return true; } // Others will not work (end object/array; reserved; shared strings) return false; } // ASCII ctrl char range is pretty good match too if (ch >= 0x80 && ch <= 0x9F) { return true; } return false; } /** * @param lenient Whether to consider more speculative matches or not * (typically true when there is context like start-array) */ private static boolean possibleSmileValue(byte b, boolean lenient) { int ch = (int) b & 0xFF; // note: we know that likely matches have been handled already, so... if (ch >= 0x80) { return (ch <= 0xE0); } if (lenient) { if (ch >= 0x40) { // tiny/short ASCII return true; } if (ch >- 0x20) { // various constants return (ch < 0x2C); // many reserved bytes that can't be seen } } return false; } /* /********************************************************** /* Internal methods, raw input access /********************************************************** */ protected boolean ensureLoaded(int minimum) throws IOException { if (_in == null) { // block source; nothing more to load return false; } /* Let's assume here buffer has enough room -- this will always * be true for the limited used this method gets */ int gotten = (_inputEnd - _inputPtr); while (gotten < minimum) { int count = _in.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd); if (count < 1) { return false; } _inputEnd += count; gotten += count; } return true; } } jackson-src-1.9.2/src/smile/java/org/codehaus/jackson/smile/SmileBufferRecycler.java0000644000175000017500000000277711655120726031137 0ustar jamespagejamespagepackage org.codehaus.jackson.smile; /** * Simple helper class used for implementing simple reuse system for Smile-specific * buffers that are used. * * @param Type of name entries stored in arrays to recycle * * @since 1.7 */ public class SmileBufferRecycler { public final static int DEFAULT_NAME_BUFFER_LENGTH = 64; public final static int DEFAULT_STRING_VALUE_BUFFER_LENGTH = 64; protected T[] _seenNamesBuffer; protected T[] _seenStringValuesBuffer; public SmileBufferRecycler() { } public T[] allocSeenNamesBuffer() { // 11-Feb-2011, tatu: Used to alloc here; but due to generics, can't easily any more T[] result = _seenNamesBuffer; if (result != null) { // let's ensure we don't retain it here, unless returned _seenNamesBuffer = null; // note: caller must have cleaned it up before returning } return result; } public T[] allocSeenStringValuesBuffer() { // 11-Feb-2011, tatu: Used to alloc here; but due to generics, can't easily any more T[] result = _seenStringValuesBuffer; if (result != null) { _seenStringValuesBuffer = null; // note: caller must have cleaned it up before returning } return result; } public void releaseSeenNamesBuffer(T[] buffer) { _seenNamesBuffer = buffer; } public void releaseSeenStringValuesBuffer(T[] buffer) { _seenStringValuesBuffer = buffer; } } jackson-src-1.9.2/src/mrbean/0000755000175000017500000000000011655120726016452 5ustar jamespagejamespagejackson-src-1.9.2/src/mrbean/java/0000755000175000017500000000000011655120726017373 5ustar jamespagejamespagejackson-src-1.9.2/src/mrbean/java/org/0000755000175000017500000000000011655120726020162 5ustar jamespagejamespagejackson-src-1.9.2/src/mrbean/java/org/codehaus/0000755000175000017500000000000011655120726021755 5ustar jamespagejamespagejackson-src-1.9.2/src/mrbean/java/org/codehaus/jackson/0000755000175000017500000000000011655120726023405 5ustar jamespagejamespagejackson-src-1.9.2/src/mrbean/java/org/codehaus/jackson/mrbean/0000755000175000017500000000000011672662540024655 5ustar jamespagejamespagejackson-src-1.9.2/src/mrbean/java/org/codehaus/jackson/mrbean/AbstractTypeMaterializer.java0000644000175000017500000002016711655120726032500 0ustar jamespagejamespagepackage org.codehaus.jackson.mrbean; import java.lang.reflect.Modifier; import org.codehaus.jackson.Version; import org.codehaus.jackson.Versioned; import org.codehaus.jackson.map.AbstractTypeResolver; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.util.VersionUtil; /** * Nifty class for pulling implementations of classes out of thin air. *

* ... friends call him Mister Bean... :-) * * @author tatu * @author sunny * * @since 1.6 */ public class AbstractTypeMaterializer extends AbstractTypeResolver implements Versioned { /** * Enumeration that defines togglable features that guide * the serialization feature. */ public enum Feature { /** * Feature that determines what happens if an "unrecognized" * (non-getter, non-setter) abstract method is encountered: if set to * true, will throw an exception during materialization; if false, * will materialize method that throws exception only if called. */ FAIL_ON_UNMATERIALIZED_METHOD(false), /** * Feature that determines what happens when attempt is made to * generate implementation of non-public class or interface. * If true, an exception is thrown; if false, will just quietly * ignore attempts. * * @since 1.9 */ FAIL_ON_NON_PUBLIC_TYPES(true) ; final boolean _defaultState; // Method that calculates bit set (flags) of all features that are enabled by default. protected static int collectDefaults() { int flags = 0; for (Feature f : values()) { if (f.enabledByDefault()) { flags |= f.getMask(); } } return flags; } private Feature(boolean defaultState) { _defaultState = defaultState; } public boolean enabledByDefault() { return _defaultState; } public int getMask() { return (1 << ordinal()); } } /** * Bitfield (set of flags) of all Features that are enabled * by default. */ protected final static int DEFAULT_FEATURE_FLAGS = Feature.collectDefaults(); /** * Default package to use for generated classes. */ public final static String DEFAULT_PACKAGE_FOR_GENERATED = "org.codehaus.jackson.generated."; /** * We will use per-materializer class loader for now; would be nice * to find a way to reduce number of class loaders (and hence * number of generated classes!) constructed... */ protected final MyClassLoader _classLoader; /** * Bit set that contains all enabled features */ protected int _featureFlags = DEFAULT_FEATURE_FLAGS; /** * Package name to use as prefix for generated classes. */ protected String _defaultPackage = DEFAULT_PACKAGE_FOR_GENERATED; /* /********************************************************** /* Construction, configuration /********************************************************** */ public AbstractTypeMaterializer() { this(null); } public AbstractTypeMaterializer(ClassLoader parentClassLoader) { if (parentClassLoader == null) { parentClassLoader = getClass().getClassLoader(); } _classLoader = new MyClassLoader(parentClassLoader); } /** * Method that will return version information stored in and read from jar * that contains this class. * * @since 1.6 */ @Override public Version version() { return VersionUtil.versionFor(getClass()); } /** * Method for checking whether given feature is enabled or not */ public final boolean isEnabled(Feature f) { return (_featureFlags & f.getMask()) != 0; } /** * Method for enabling specified feature. */ public void enable(Feature f) { _featureFlags |= f.getMask(); } /** * Method for disabling specified feature. */ public void disable(Feature f) { _featureFlags &= ~f.getMask(); } /** * Method for enabling or disabling specified feature. */ public void set(Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } } public void setDefaultPackage(String defPkg) { if (!defPkg.endsWith(".")) { defPkg = defPkg + "."; } _defaultPackage = defPkg; } /* /********************************************************** /* Public API /********************************************************** */ @Override public JavaType resolveAbstractType(DeserializationConfig config, JavaType type) { /* 19-Feb-2011, tatu: Future plans may include calling of this method for all kinds * of abstract types. So as simple precaution, let's limit kinds of types we * will try materializa implementations for. */ /* We won't be handling any container types (Collections, Maps and arrays), * Throwables or enums. */ if (type.isContainerType() || type.isPrimitive() || type.isEnumType() || type.isThrowable()) { return null; } Class cls = type.getRawClass(); /* [JACKSON-683] Fail on non-public classes, since we can't easily force * access to such classes (unless we tried to generate impl classes in that * package) */ if (!Modifier.isPublic(cls.getModifiers())) { if (isEnabled(Feature.FAIL_ON_NON_PUBLIC_TYPES)) { throw new IllegalArgumentException("Can not materialize implementation of "+cls+" since it is not public "); } return null; } // might want to skip proxies, local types too... but let them be for now: //if (intr.findTypeResolver(beanDesc.getClassInfo(), type) == null) { return config.constructType(materializeClass(config, cls)); } /* /********************************************************** /* Internal methods /********************************************************** */ protected Class materializeClass(DeserializationConfig config, Class cls) { // Need to have proper name mangling in future, but for now... String newName = _defaultPackage+cls.getName(); BeanBuilder builder = new BeanBuilder(config, cls); byte[] bytecode = builder.implement(isEnabled(Feature.FAIL_ON_UNMATERIALIZED_METHOD)).build(newName); Class result = _classLoader.loadAndResolve(newName, bytecode, cls); return result; } /* /********************************************************** /* Helper classes /********************************************************** */ /** * To support actual dynamic loading of bytecode we need a simple * custom classloader. */ private static class MyClassLoader extends ClassLoader { public MyClassLoader(ClassLoader parent) { super(parent); } /** * @param targetClass Interface or abstract class that class to load should extend or * implement */ public Class loadAndResolve(String className, byte[] byteCode, Class targetClass) throws IllegalArgumentException { // First things first: just to be sure; maybe we have already loaded it? Class old = findLoadedClass(className); if (old != null && targetClass.isAssignableFrom(old)) { return old; } Class impl; try { impl = defineClass(className, byteCode, 0, byteCode.length); } catch (LinkageError e) { throw new IllegalArgumentException("Failed to load class '"+className+"': "+e.getMessage() ,e); } // important: must also resolve the class... resolveClass(impl); return impl; } } } jackson-src-1.9.2/src/mrbean/java/org/codehaus/jackson/mrbean/BeanUtil.java0000644000175000017500000000401111655120726027213 0ustar jamespagejamespagepackage org.codehaus.jackson.mrbean; import java.lang.reflect.Member; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class BeanUtil { protected static boolean isConcrete(Member member) { int mod = member.getModifiers(); return (mod & (Modifier.INTERFACE | Modifier.ABSTRACT)) == 0; } /** * Method that will find all sub-classes and implemented interfaces * of a given class or interface. Classes are listed in order of * precedence, starting with the immediate super-class, followed by * interfaces class directly declares to implemented, and then recursively * followed by parent of super-class and so forth. * Note that Object.class is not included in the list * regardless of whether endBefore argument is defined or not. * * @param endBefore Super-type to NOT include in results, if any; when * encountered, will be ignored (and no super types are checked). */ public static List> findSuperTypes(Class cls, Class endBefore) { return findSuperTypes(cls, endBefore, new ArrayList>()); } public static List> findSuperTypes(Class cls, Class endBefore, List> result) { _addSuperTypes(cls, endBefore, result, false); return result; } private static void _addSuperTypes(Class cls, Class endBefore, Collection> result, boolean addClassItself) { if (cls == endBefore || cls == null || cls == Object.class) { return; } if (addClassItself) { if (result.contains(cls)) { // already added, no need to check supers return; } result.add(cls); } for (Class intCls : cls.getInterfaces()) { _addSuperTypes(intCls, endBefore, result, true); } _addSuperTypes(cls.getSuperclass(), endBefore, result, true); } } jackson-src-1.9.2/src/mrbean/java/org/codehaus/jackson/mrbean/MrBeanModule.java0000644000175000017500000000255111655120726030031 0ustar jamespagejamespagepackage org.codehaus.jackson.mrbean; import org.codehaus.jackson.Version; import org.codehaus.jackson.map.Module; import org.codehaus.jackson.mrbean.AbstractTypeMaterializer; public class MrBeanModule extends Module { private final String NAME = "MrBeanModule"; // TODO: externalize private final static Version VERSION = new Version(1, 8, 0, null); /** * Configured materializer instance to register with deserializer factory. */ protected AbstractTypeMaterializer _materializer; /* /********************************************************** /* Life-cycle /********************************************************** */ public MrBeanModule() { this(new AbstractTypeMaterializer()); } public MrBeanModule(AbstractTypeMaterializer materializer) { _materializer = materializer; } @Override public String getModuleName() { return NAME; } @Override public Version version() { return VERSION; } @Override public void setupModule(SetupContext context) { // All we really need to for now is to register materializer: context.addAbstractTypeResolver(_materializer); } /* /********************************************************** /* Extended API, configuration /********************************************************** */ } jackson-src-1.9.2/src/mrbean/java/org/codehaus/jackson/mrbean/BeanBuilder.java0000644000175000017500000004103311655120726027671 0ustar jamespagejamespagepackage org.codehaus.jackson.mrbean; import java.lang.reflect.Method; import java.util.*; import org.codehaus.jackson.org.objectweb.asm.*; import static org.codehaus.jackson.org.objectweb.asm.Opcodes.*; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.type.TypeFactory; /** * Heavy lifter of mr Bean package: class that keeps track of logical POJO properties, * and figures out how to create an implementation class. * * @since 1.6 */ public class BeanBuilder { protected Map _beanProperties = new LinkedHashMap(); protected LinkedHashMap _unsupportedMethods = new LinkedHashMap(); /** * Abstract class or interface that the bean is created to extend or implement. */ protected final Class _implementedType; protected final TypeFactory _typeFactory; public BeanBuilder(DeserializationConfig config, Class implType) { _implementedType = implType; _typeFactory = config.getTypeFactory(); } /* /********************************************************** /* Core public API /********************************************************** */ /** * @param failOnUnrecognized If true, and an unrecognized (non-getter, non-setter) * method is encountered, will throw {@link IllegalArgumentException}; if false, * will implement bogus method that will throw {@link UnsupportedOperationException} * if called. */ public BeanBuilder implement(boolean failOnUnrecognized) { ArrayList> implTypes = new ArrayList>(); // First: find all supertypes: implTypes.add(_implementedType); BeanUtil.findSuperTypes(_implementedType, Object.class, implTypes); for (Class impl : implTypes) { // and then find all getters, setters, and other non-concrete methods therein: for (Method m : impl.getDeclaredMethods()) { String methodName = m.getName(); int argCount = m.getParameterTypes().length; if (argCount == 0) { // getter? if (methodName.startsWith("get") || methodName.startsWith("is") && returnsBoolean(m)) { addGetter(m); continue; } } else if (argCount == 1 && methodName.startsWith("set")) { addSetter(m); continue; } // Otherwise, if concrete, or already handled, skip: // !!! note: won't handle overloaded methods properly if (BeanUtil.isConcrete(m) || _unsupportedMethods.containsKey(methodName)) { continue; } if (failOnUnrecognized) { throw new IllegalArgumentException("Unrecognized abstract method '"+methodName +"' (not a getter or setter) -- to avoid exception, disable AbstractTypeMaterializer.Feature.FAIL_ON_UNMATERIALIZED_METHOD"); } _unsupportedMethods.put(methodName, m); } } return this; } /** * Method that generates byte code for class that implements abstract * types requested so far. * * @param className Fully-qualified name of the class to generate * @return Byte code Class instance built by this builder */ public byte[] build(String className) { ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); String internalClass = getInternalClassName(className); String implName = getInternalClassName(_implementedType.getName()); // muchos important: level at least 1.5 to get generics!!! // Also: abstract class vs interface... String superName; if (_implementedType.isInterface()) { superName = "java/lang/Object"; cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, internalClass, null, superName, new String[] { implName }); } else { superName = implName; cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, internalClass, null, implName, null); } cw.visitSource(className + ".java", null); BeanBuilder.generateDefaultConstructor(cw, superName); for (Property prop : _beanProperties.values()) { // First: determine type to use; preferably setter (usually more explicit); otherwise getter TypeDescription type = prop.selectType(_typeFactory); createField(cw, prop, type); // since some getters and/or setters may be implemented, check: if (!prop.hasConcreteGetter()) { createGetter(cw, internalClass, prop, type); } if (!prop.hasConcreteSetter()) { createSetter(cw, internalClass, prop, type); } } for (Method m : _unsupportedMethods.values()) { createUnimplementedMethod(cw, internalClass, m); } cw.visitEnd(); return cw.toByteArray(); } /* /********************************************************** /* Internal methods, property discovery /********************************************************** */ private static String getPropertyName(String methodName) { int prefixLen = methodName.startsWith("is") ? 2 : 3; String body = methodName.substring(prefixLen); StringBuilder sb = new StringBuilder(body); sb.setCharAt(0, Character.toLowerCase(body.charAt(0))); return sb.toString(); } private static String buildGetterName(String fieldName) { return "get" + fieldName.substring(0, 1).toUpperCase()+ fieldName.substring(1); } private static String buildSetterName(String fieldName) { return "set" + fieldName.substring(0, 1).toUpperCase()+ fieldName.substring(1); } private static String getInternalClassName(String className) { return className.replace(".", "/"); } private void addGetter(Method m) { Property prop = findProperty(getPropertyName(m.getName())); // only set if not yet set; we start with super class: if (prop.getGetter() == null) { prop.setGetter(m); } } private void addSetter(Method m) { Property prop = findProperty(getPropertyName(m.getName())); if (prop.getSetter() == null) { prop.setSetter(m); } } private Property findProperty(String propName) { Property prop = _beanProperties.get(propName); if (prop == null) { prop = new Property(propName); _beanProperties.put(propName, prop); } return prop; } private final static boolean returnsBoolean(Method m) { Class rt = m.getReturnType(); return (rt == Boolean.class || rt == Boolean.TYPE); } /* /********************************************************** /* Internal methods, bytecode generation /********************************************************** */ private static void generateDefaultConstructor(ClassWriter cw, String superName) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, superName, "", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); // don't care (real values: 1,1) mv.visitEnd(); } private static void createField(ClassWriter cw, Property prop, TypeDescription type) { String sig = type.hasGenerics() ? type.genericSignature() : null; String desc = type.erasedSignature(); FieldVisitor fv = cw.visitField(ACC_PUBLIC, prop.getFieldName(), desc, sig, null); fv.visitEnd(); } private static void createSetter(ClassWriter cw, String internalClassName, Property prop, TypeDescription propertyType) { String methodName; String desc; Method setter = prop.getSetter(); if (setter != null) { // easy, copy as is desc = Type.getMethodDescriptor(setter); methodName = setter.getName(); } else { // otherwise need to explicitly construct from property type (close enough) desc = "("+ propertyType.erasedSignature() + ")V"; methodName = buildSetterName(prop.getName()); } String sig = propertyType.hasGenerics() ? ("("+propertyType.genericSignature()+")V") : null; MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, desc, sig, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); // this mv.visitVarInsn(propertyType.getLoadOpcode(), 1); mv.visitFieldInsn(PUTFIELD, internalClassName, prop.getFieldName(), propertyType.erasedSignature()); mv.visitInsn(RETURN); mv.visitMaxs(0, 0); // don't care (real values: 2, 2) mv.visitEnd(); } private static void createGetter(ClassWriter cw, String internalClassName, Property prop, TypeDescription propertyType) { String methodName; String desc; Method getter = prop.getGetter(); if (getter != null) { // easy, copy as is desc = Type.getMethodDescriptor(getter); methodName = getter.getName(); } else { // otherwise need to explicitly construct from property type (close enough) desc = "()"+propertyType.erasedSignature(); methodName = buildGetterName(prop.getName()); } String sig = propertyType.hasGenerics() ? ("()"+propertyType.genericSignature()) : null; MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, desc, sig, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); // load 'this' mv.visitFieldInsn(GETFIELD, internalClassName, prop.getFieldName(), propertyType.erasedSignature()); mv.visitInsn(propertyType.getReturnOpcode()); mv.visitMaxs(0, 0); // don't care (real values: 1,1) mv.visitEnd(); } /** * Builder for methods that just throw an exception, basically "unsupported * operation" implementation. */ private static void createUnimplementedMethod(ClassWriter cw, String internalClassName, Method method) { String exceptionName = getInternalClassName(UnsupportedOperationException.class.getName()); String sig = Type.getMethodDescriptor(method); String name = method.getName(); // should we try to pass generic information? MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, name, sig, null, null); mv.visitTypeInsn(NEW, exceptionName); mv.visitInsn(DUP); mv.visitLdcInsn("Unimplemented method '"+name+"' (not a setter/getter, could not materialize)"); mv.visitMethodInsn(INVOKESPECIAL, exceptionName, "", "(Ljava/lang/String;)V"); mv.visitInsn(ATHROW); mv.visitMaxs(0, 0); // don't care (real values: 3, 1 + method.getParameterTypes().length); mv.visitEnd(); } /* /********************************************************** /* Helper classes /********************************************************** */ /** * Bean that contains information about a single logical * property, which consists of a getter and/or setter, * and is used to generate getter, setter and matching * backing field. */ private static class Property { protected final String _name; protected final String _fieldName; protected Method _getter; protected Method _setter; public Property(String name) { _name = name; // Let's just prefix field name with single underscore for fun... _fieldName = "_"+name; } public String getName() { return _name; } public void setGetter(Method m) { _getter = m; } public void setSetter(Method m) { _setter = m; } public Method getGetter() { return _getter; } public Method getSetter() { return _setter; } public String getFieldName() { return _fieldName; } /* private static boolean isConcrete(Method m) { return m.getModifiers() } */ public boolean hasConcreteGetter() { return (_getter != null) && BeanUtil.isConcrete(_getter); } public boolean hasConcreteSetter() { return (_setter != null) && BeanUtil.isConcrete(_setter); } private TypeDescription getterType(TypeFactory tf) { Class context = _getter.getDeclaringClass(); return new TypeDescription(tf.constructType(_getter.getGenericReturnType(), context)); } private TypeDescription setterType(TypeFactory tf) { Class context = _setter.getDeclaringClass(); return new TypeDescription(tf.constructType(_setter.getGenericParameterTypes()[0], context)); } public TypeDescription selectType(TypeFactory tf) { // First: if only know setter, or getter, use that one: if (_getter == null) { return setterType(tf); } if (_setter == null) { return getterType(tf); } /* Otherwise must ensure they are compatible, choose more specific * (most often setter - type) */ TypeDescription st = setterType(tf); TypeDescription gt = getterType(tf); TypeDescription specificType = TypeDescription.moreSpecificType(st, gt); if (specificType == null) { // incompatible... throw new IllegalArgumentException("Invalid property '"+getName() +"': incompatible types for getter/setter (" +gt+" vs "+st+")"); } return specificType; } } /** * Helper bean used to encapsulate most details of type handling */ private static class TypeDescription { private final Type _asmType; private JavaType _jacksonType; /* /********************************************************** /* Construction /********************************************************** */ public TypeDescription(JavaType type) { _jacksonType = type; _asmType = Type.getType(type.getRawClass()); } /* /********************************************************** /* Accessors /********************************************************** */ public Class getRawClass() { return _jacksonType.getRawClass(); } public String erasedSignature() { return _jacksonType.getErasedSignature(); } public String genericSignature() { return _jacksonType.getGenericSignature(); } /** * @return True if type has direct generic declaration (which may need * to be copied) */ public boolean hasGenerics() { return _jacksonType.hasGenericTypes(); } /* public boolean isPrimitive() { return _signature.length() == 1; } */ /* public int getStoreOpcode() { return _signatureType.getOpcode(ISTORE); } */ public int getLoadOpcode() { return _asmType.getOpcode(ILOAD); } public int getReturnOpcode() { return _asmType.getOpcode(IRETURN); } @Override public String toString() { return _jacksonType.toString(); } /* /********************************************************** /* Other methods /********************************************************** */ public static TypeDescription moreSpecificType(TypeDescription desc1, TypeDescription desc2) { Class c1 = desc1.getRawClass(); Class c2 = desc2.getRawClass(); if (c1.isAssignableFrom(c2)) { // c2 more specific than c1 return desc2; } if (c2.isAssignableFrom(c1)) { // c1 more specific than c2 return desc1; } // not compatible, so: return null; } } } jackson-src-1.9.2/src/mrbean/java/org/codehaus/jackson/mrbean/package-info.java0000644000175000017500000000034511655120726030042 0ustar jamespagejamespage/** * Package that implements "interface materializer" functionality, whereby * abstract classes and interfaces can be used as-is, and framework constructs * implementations as needed. */ package org.codehaus.jackson.mrbean; jackson-src-1.9.2/src/tools/0000755000175000017500000000000011672662540016352 5ustar jamespagejamespagejackson-src-1.9.2/src/tools/GenerateIntDoc.java0000644000175000017500000000370111655120726022045 0ustar jamespagejamespage import java.io.*; import java.util.Random; import org.codehaus.jackson.*; public class GenerateIntDoc { final static int AVG_ARRAY_LEN = 32; private GenerateIntDoc() { } private void generate(OutputStream out, int kbSize) throws IOException { int bsize = kbSize * 1000; // Let's first buffer in memory, to know exact length ByteArrayOutputStream bos = new ByteArrayOutputStream(bsize + 500); Random r = new Random(kbSize); JsonGenerator gen = new JsonFactory().createJsonGenerator(bos, JsonEncoding.UTF8); gen.writeStartArray(); // outermost array gen.writeStartArray(); // inner array do { // First, do we close current, start new array? if (r.nextInt(AVG_ARRAY_LEN) == 3) { // to get average array length of 16 gen.writeEndArray(); if (r.nextBoolean()) { gen.writeRaw("\n"); } gen.writeStartArray(); gen.flush(); } // Then need to calculate number to output int nr = r.nextInt(32); if (r.nextBoolean()) { nr *= r.nextInt(256); // up to 8k if (r.nextBoolean()) { nr *= r.nextInt(0x20000); // up to 1G } } if (r.nextBoolean()) { nr = -nr; } gen.writeNumber(nr); } while (bos.size() < bsize); gen.writeEndArray(); gen.writeEndArray(); gen.writeRaw("\n"); gen.close(); bos.writeTo(out); } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java test.GenerateIntDoc "); System.exit(1); } new GenerateIntDoc().generate(System.out, Integer.parseInt(args[0])); System.out.flush(); } } jackson-src-1.9.2/src/tools/TestSerializationError.java0000644000175000017500000000174111655120726023703 0ustar jamespagejamespageimport java.io.*; import java.util.*; import org.codehaus.jackson.map.*; public class TestSerializationError { final static class OkBean { ArrayList _beans; public OkBean() { _beans = new ArrayList(); _beans.add(new NonBean[] { new NonBean() });; } public List getNonBeans() { return _beans; } } final static class NonBean { public NonBean() { } } public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); ArrayList list = new ArrayList(); list.add(new OkBean()); HashMap map = new HashMap(); map.put("foo", list); // should error out, but what do we see there? StringWriter sw = new StringWriter(); mapper.writeValue(sw, map); System.out.println("Odd, didn't fail, got: "+sw.toString()); } } jackson-src-1.9.2/src/tools/CheckNumberSpeed.java0000644000175000017500000000502211655120726022357 0ustar jamespagejamespageimport java.math.BigInteger; /** * Simple test to see what is the performance difference between converting * simple int values into different wrapper types. */ public final class CheckNumberSpeed { final int[] data; final static int REPS = 2000; private CheckNumberSpeed() { data = new int[1200]; for (int i = 0; i < data.length; ++i) { // mostly small positive numbers, some negative data[i] = i - 100; } } public void test() throws Exception { int nr = 0; while (true) { int type = (nr++) % 4; long start = System.nanoTime(); String str; Object o; switch (type) { case 0: o = testIntsValueOf(data); str = "int/share"; break; case 1: o = testIntsCreate(data); str = "int/create"; break; case 2: o = testLongs(data); str = "longs"; break; default: o = testBigInts(data); str = "BigInts"; break; } long time = System.nanoTime() - start; time = time >> 10; // from nano to micro System.out.println("Time for '"+str+"' -> "+time+" us (hash: "+o.hashCode()+")"); Thread.sleep(200L); } } Integer testIntsValueOf(int[] ints) { Integer v = null; int reps = REPS; while (--reps > 0) { for (int value : ints) { v = Integer.valueOf(value); } } return v; } Integer testIntsCreate(int[] ints) { Integer v = null; int reps = REPS; while (--reps > 0) { for (int value : ints) { v = new Integer(value); } } return v; } Long testLongs(int[] ints) { Long v = null; int reps = REPS; while (--reps > 0) { for (int value : ints) { v = Long.valueOf(value); } } return v; } BigInteger testBigInts(int[] ints) { BigInteger v = null; int reps = REPS; while (--reps > 0) { for (int value : ints) { v = BigInteger.valueOf(value); } } return v; } public static void main(String[] args) throws Exception { new CheckNumberSpeed().test(); } } jackson-src-1.9.2/src/tools/TestReflection.java0000644000175000017500000000765511655120726022160 0ustar jamespagejamespage import java.lang.reflect.*; import java.util.*; /** * Manually run class used for figuring out exactly how JDK/generics * expose type information. */ @SuppressWarnings("serial") public class TestReflection extends ArrayList { public static void main(String[] args) throws Exception { TestReflection test = new TestReflection(); test.test0(); } @SuppressWarnings("unused") private void test() throws Exception { //Class cls1 = ArrayList.class; //Class cls2 = new ArrayList().getClass(); Class cls1 = ArrayList[].class; Class cls2 = List[].class; System.out.println("Cls 1 = "+cls1); System.out.println("Cls 2 = "+cls2); System.out.println("1 === 2? "+(cls1 == cls2)); System.out.println("1 == 2? "+(cls1.equals(cls2))); } private void test0() throws Exception { testMethod(getClass().getMethod("methodPlain")); testMethod(getClass().getMethod("methodParam")); testMethod(getClass().getMethod("methodArrayPlain")); testMethod(getClass().getMethod("methodArrayParam")); testMethod(getClass().getMethod("methodWildcard")); } public LinkedHashMap, Boolean[]> methodParam() { return null; } public Integer methodPlain() { return null; } public int[][][] methodArrayPlain() { return null; } public LinkedList>>[][][] methodArrayParam() { return null; } public Set> methodWildcard() { return null; } private void testMethod(Method m) throws Exception { System.out.println("Return type for ["+m+"]:"); //int ix = 0; Type type = m.getGenericReturnType(); printType(1, type); } private void indent(int amount) { for (int i = 0; i < amount; ++i) { System.out.print(" "); } } private void printType(int indent, Type type) { indent(indent); if (type == null) { System.out.println("[null]"); } else if (type instanceof Class) { System.out.println("simple class: "+((Class) type).getName()); } else if (type instanceof GenericArrayType) { System.out.println("array type, component:"); GenericArrayType at = (GenericArrayType) type; printType(indent+1, at.getGenericComponentType()); } else if (type instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) type; System.out.println("parameterized type:"); ++indent; indent(indent); System.out.println("owner -> "); printType(indent+1, pt.getOwnerType()); indent(indent); System.out.println("raw -> "); printType(indent+1, pt.getRawType()); int ix = 0; for (Type t2 : pt.getActualTypeArguments()) { ++ix; indent(indent); System.out.println("actual #"+ix+" -> "); printType(indent+1, t2); } } else if (type instanceof TypeVariable) { TypeVariable v = (TypeVariable) type; System.out.println("type variable '"+v.getName()+"'"); } else if (type instanceof WildcardType) { WildcardType w = (WildcardType) type; System.out.println("wildcard type:"); ++indent; indent(indent); System.out.println("lower bounds[] -> "); for (Type t2 : w.getLowerBounds()) { printType(indent+1, t2); } indent(indent); System.out.println("upper bounds[] -> "); for (Type t2 : w.getUpperBounds()) { printType(indent+1, t2); } } else { throw new IllegalArgumentException("Weird type! "+type.getClass()); } } } jackson-src-1.9.2/src/tools/TestObjectMapper.java0000644000175000017500000000234211655120726022425 0ustar jamespagejamespageimport java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; public class TestObjectMapper { private TestObjectMapper() { } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java test.TestObjectMapper "); System.exit(1); } FileInputStream in = new FileInputStream(new File(args[0])); JsonFactory f = new JsonFactory(); JsonParser jp = f.createJsonParser(in); ObjectMapper map = new ObjectMapper(); // 06-Jan-2009, tatu: This will mean "untyped" mapping Object result = map.readValue(jp, Object.class); jp.close(); System.out.println("Read result ("+(result.getClass())+"): <"+result+">"); StringWriter sw = new StringWriter(); JsonGenerator jg = f.createJsonGenerator(sw); try { map.writeValue(jg, result); } catch (Exception e) { try { jg.flush(); } catch (IOException ioe) { } System.err.println("Error, intermediate result = |"+sw+"|"); throw e; } jg.close(); System.out.println("Write result: <"+sw.toString()+">"); } } jackson-src-1.9.2/src/tools/TestBeanMapper.java0000644000175000017500000000317411655120726022070 0ustar jamespagejamespage import java.io.*; import java.util.*; import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; public class TestBeanMapper { private TestBeanMapper() { } private void test() throws Exception { JsonFactory f = new JsonFactory(); ObjectMapper jmap = new ObjectMapper(); Object foo = new MyObject(5, -90, "Desc"); StringWriter sw = new StringWriter(); JsonGenerator jg = f.createJsonGenerator(sw); try { jmap.writeValue(jg, foo); } catch (Exception e) { try { jg.flush(); } catch (IOException ioe) { } System.err.println("Error, intermediate result = |"+sw+"|"); throw e; } jg.close(); System.out.println("Write result: <"+sw.toString()+">"); } public static void main(String[] args) throws Exception { new TestBeanMapper().test(); } @SuppressWarnings("unused") private final class MyObject { final int _x, _y; final String _desc; public MyObject(int x, int y, String desc) { _x = x; _y = y; _desc = desc; } public String getDesc() { return _desc; } public int getX() { return _x; } public int getY() { return _y; } public int[] getFoobar() { return new int[] { 1, 2, 3 }; } public MyObject2 getNext() { return new MyObject2(); } public Collection getMisc() { return new ArrayList(); } } final static class MyObject2 { public String getName() { return "dummy"; } } } jackson-src-1.9.2/src/tools/GenerateDoubleDoc.java0000644000175000017500000000344411655120726022531 0ustar jamespagejamespage import java.io.*; import java.util.Random; import org.codehaus.jackson.*; public class GenerateDoubleDoc { final static int AVG_ARRAY_LEN = 32; private GenerateDoubleDoc() { } private void generate(OutputStream out, int kbSize) throws IOException { int bsize = kbSize * 1000; // Let's first buffer in memory, to know exact length ByteArrayOutputStream bos = new ByteArrayOutputStream(bsize + 500); Random r = new Random(kbSize); JsonGenerator gen = new JsonFactory().createJsonGenerator(bos, JsonEncoding.UTF8); gen.writeStartArray(); // outermost array gen.writeStartArray(); // inner array do { // First, do we close current, start new array? if (r.nextInt(AVG_ARRAY_LEN) == 3) { // to get average array length of 16 gen.writeEndArray(); if (r.nextBoolean()) { gen.writeRaw("\n"); } gen.writeStartArray(); gen.flush(); } // Then need to calculate number to output float f; do { f = Float.intBitsToFloat(r.nextInt()); } while (Double.isNaN(f) || Double.isInfinite(f)); gen.writeNumber(f); } while (bos.size() < bsize); gen.writeEndArray(); gen.writeEndArray(); gen.writeRaw("\n"); gen.close(); bos.writeTo(out); } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java test.GenerateDoubleDoc "); System.exit(1); } new GenerateDoubleDoc().generate(System.out, Integer.parseInt(args[0])); System.out.flush(); } } jackson-src-1.9.2/src/tools/TestParser.java0000644000175000017500000000324411655120726021310 0ustar jamespagejamespage import java.io.*; import org.codehaus.jackson.*; public class TestParser { public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Usage: java ... TestParser [file]"); System.exit(1); } JsonFactory f = new JsonFactory(); // [JACKSON-259]: ability to suppress canonicalization f.disable(JsonParser.Feature.CANONICALIZE_FIELD_NAMES); JsonParser jp = f.createJsonParser(new File(args[0])); //JsonParser jp = f.createJsonParser(new InputStreamReader(new FileInputStream(args[0]), "UTF-8")); jp.enable(JsonParser.Feature.ALLOW_COMMENTS); System.out.println("Parser: "+jp); JsonToken t; while ((t = jp.nextToken()) != null) { System.out.print("Token: "+t); if (t == JsonToken.FIELD_NAME) { //String name = new String(jp.getTextCharacters(), jp.getTextOffset(), jp.getTextLength()); String name = jp.getCurrentName(); System.out.print(", name = '"+name+"' (len: "+name.length()+")"); // Troubleshoot: int ix = name.indexOf('\0'); if (ix >= 0) { throw new RuntimeException("Null byte for name, at index #"+ix); } } else if (t.toString().startsWith("VALUE")) { if (t == JsonToken.VALUE_STRING) { System.out.print(" [len: "+jp.getTextLength()+"]"); } System.out.print(", value = \""+jp.getText()+"\""); } System.out.println(); } jp.close(); } } jackson-src-1.9.2/src/tools/TestGenerator.java0000644000175000017500000000143211655120726021777 0ustar jamespagejamespage import java.io.*; import java.math.BigDecimal; import org.codehaus.jackson.*; public class TestGenerator { private TestGenerator() { } public static void main(String[] args) throws Exception { StringWriter strw = new StringWriter(); JsonGenerator jg = new JsonFactory().createJsonGenerator(strw); jg.writeStartObject(); jg.writeFieldName("pi"); //jg.writeNumber(new BigDecimal("1.23")); jg.writeNumber(new BigDecimal("1.23")); jg.writeFieldName("binary"); byte[] data = "Test string!".getBytes("UTF-8"); jg.writeBinary(data); // what happens if we leave this out? //jg.writeEndObject(); jg.close(); System.out.println("Result: <"+strw.toString()+">"); } } jackson-src-1.9.2/src/tools/TestMapSpeed.java0000644000175000017500000001301411655120726021546 0ustar jamespagejamespageimport java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; public final class TestMapSpeed { /** * Number of repetitions to run per test. Dynamically variable, * based on observed runtime, to try to keep it high enough. */ private int REPS; /** * Let's keep per-run times above 50 milliseconds */ //final static int MIN_RUN_TIME = 50; final static int MIN_RUN_TIME = 5; /** * Let's keep per-run times below 300 milliseconds */ //final static int MAX_RUN_TIME = 300; final static int MAX_RUN_TIME = 1000; private final static int TEST_PER_GC = 17; final JsonFactory _factory; final ObjectMapper _mapper; final Object _objectToMap; private TestMapSpeed(byte[] data) throws Exception { _factory = new JsonFactory(); _mapper = new ObjectMapper(); JsonParser jp = _factory.createJsonParser(data, 0, data.length); _objectToMap = _mapper.readValue(jp, Object.class); jp.close(); // Ok how should we guestimate speed... perhaps from data size? REPS = 100 + ((8 * 1000 * 1000) / data.length); System.out.println("Based on size, will use "+REPS+" repetitions"); } protected int test() throws Exception { int i = 0; int total = 0; final int TEST_CASES = 2; final ByteArrayOutputStream bos = new ByteArrayOutputStream(1000); while (true) { try { Thread.sleep(150L); } catch (InterruptedException ie) { } int round = (i++ % TEST_CASES); long now = System.currentTimeMillis(); String msg; int sum = 0; //round = 1; // testing just old or new? switch (round) { case 0: msg = "Map using OLD"; sum = testOld(REPS, bos); break; case 1: msg = "Map using NEW"; sum = testNew(REPS, bos); break; default: throw new Error("Internal error"); } now = System.currentTimeMillis() - now; if (round == 0) { System.out.println(); } System.out.println("Test '"+msg+"' -> "+now+" msecs (" +sum+" -> "+(total & 0xFF)+")."); total += sum; if ((i % TEST_PER_GC) == 0) { System.out.println("[GC]"); try { Thread.sleep(100L); } catch (InterruptedException ie) { } System.gc(); try { Thread.sleep(200L); } catch (InterruptedException ie) { } /* One more tweak: let's add load if things start * running too fast or slow, to try to get sweet range * of 50 to 250 millisseconds */ if (now < MIN_RUN_TIME) { REPS += (REPS / 5); // 20% up System.out.println("[NOTE: increasing reps, now: "+REPS+"]"); try { Thread.sleep(200L); } catch (InterruptedException ie) { } } else if (now > MAX_RUN_TIME && i > 20) { /* Let's reduce load slower than increase; also, * due to initial warmup, let's not adjust until * we've gone through a few cycles */ REPS -= (REPS / 10); // 10% down System.out.println("[NOTE: decreasing reps, now: "+REPS+"]"); try { Thread.sleep(200L); } catch (InterruptedException ie) { } } } } } /* ///////////////////////////////////////////////////////// // Actual value type access, ones via Stax 1.0 ///////////////////////////////////////////////////////// */ protected int testOld(int reps, ByteArrayOutputStream out) throws Exception { int total = 0; for (int i = 0; i < reps; ++i) { out.reset(); JsonGenerator jg = _factory.createJsonGenerator(out, JsonEncoding.UTF8); _mapper.writeValue(jg, _objectToMap); jg.close(); total = out.size(); } return total; } protected int testNew(int reps, ByteArrayOutputStream out) throws Exception { int total = 0; for (int i = 0; i < reps; ++i) { out.reset(); JsonGenerator jg = _factory.createJsonGenerator(out, JsonEncoding.UTF8); _mapper.writeValue(jg, _objectToMap); jg.close(); total = out.size(); } return total; } /* ///////////////////////////////////////////////////////// // Helper methods ///////////////////////////////////////////////////////// */ static byte[] readData(File file) throws IOException { InputStream fin = new FileInputStream(file); byte[] buf = new byte[4000]; ByteArrayOutputStream bos = new ByteArrayOutputStream(4000); int count; while ((count = fin.read(buf)) > 0) { bos.write(buf, 0, count); } fin.close(); return bos.toByteArray(); } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java ... "); System.exit(1); } byte[] data = readData(new File(args[0])); System.out.println(" -> "+data.length+" bytes read."); new TestMapSpeed(data).test(); } } jackson-src-1.9.2/src/tools/VerifySmileDocs.java0000644000175000017500000001222711655120726022264 0ustar jamespagejamespageimport java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.smile.SmileFactory; import org.codehaus.jackson.smile.SmileGenerator; /** * Helper test class that will check to see that we can round-trip * JSON-to-Smile-to-JSON, without loss of data. */ public class VerifySmileDocs { private final static JsonFactory jsonFactory = new JsonFactory(); private final static SmileFactory smileFactoryWithNoBackrefs = new SmileFactory(); { smileFactoryWithNoBackrefs.configure(SmileGenerator.Feature.CHECK_SHARED_NAMES, false); smileFactoryWithNoBackrefs.configure(SmileGenerator.Feature.CHECK_SHARED_STRING_VALUES, false); } private final static SmileFactory jsonFactoryWithBackrefs = new SmileFactory(); { jsonFactoryWithBackrefs.configure(SmileGenerator.Feature.CHECK_SHARED_NAMES, true); jsonFactoryWithBackrefs.configure(SmileGenerator.Feature.CHECK_SHARED_STRING_VALUES, true); } private VerifySmileDocs() {} private void verifyAll(File inputDir) throws IOException { File[] files = inputDir.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { int i = name.lastIndexOf('.'); if (i > 0) { String suffix = name.substring(i+1); if ("json".equals(suffix) || "jsn".equals(suffix)) { return true; } } return false; } }); if (files.length == 0) { throw new IOException("No files with suffix '.json' or '.jsn' found from under '" + inputDir.getAbsolutePath()+"'"); } System.out.printf("Found %d JSON files to test with...\n", files.length); int failures = 0; for (File file : files) { System.out.printf(" verifying file '%s'...", file.getName()); if (!verify(file, false) || !verify(file, true)) { ++failures; } else { System.out.println(" OK"); } } System.out.printf("Done: %d files had issues\n", failures); } private boolean verify(File inputFile, boolean backrefs) throws IOException { JsonFactory smileFactory = backrefs ? jsonFactoryWithBackrefs : smileFactoryWithNoBackrefs; byte[] smileDoc = convertToSmile(inputFile, smileFactory); JsonParser jpWithDiff = compareJsonToSmile(inputFile, smileDoc, smileFactory); if (jpWithDiff != null) { System.err.printf(" events differ (expected %s), location (backrefs: %s): %s\n", String.valueOf(jpWithDiff.getCurrentToken()), backrefs, inputFile.getName()); jpWithDiff.close(); return false; } return true; } private byte[] convertToSmile(File inputFile, JsonFactory outputFactory) throws IOException { ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000); JsonParser jp = jsonFactory.createJsonParser(inputFile); JsonGenerator jgen = outputFactory.createJsonGenerator(bytes); while (jp.nextToken() != null) { jgen.copyCurrentEvent(jp); } jp.close(); jgen.close(); return bytes.toByteArray(); } private JsonParser compareJsonToSmile(File inputFile, byte[] smileBytes, JsonFactory smileFactory) throws IOException { JsonParser jsonParser = jsonFactory.createJsonParser(inputFile); JsonParser smileParser = smileFactory.createJsonParser(smileBytes); JsonToken t1; while ((t1 = jsonParser.nextToken()) != null) { JsonToken t2 = smileParser.nextToken(); // first: token types must match if (t1 != t2) { return jsonParser; } // and second, values as well switch (t1) { case VALUE_STRING: case FIELD_NAME: if (!jsonParser.getText().equals(smileParser.getText())) { return jsonParser; } break; case VALUE_NUMBER_INT: if (jsonParser.getLongValue() != smileParser.getLongValue()) { return jsonParser; } break; case VALUE_NUMBER_FLOAT: if (jsonParser.getDoubleValue() != smileParser.getDoubleValue()) { return jsonParser; } break; // others are fine: // Boolean values are distinct tokens; // Object/Array start/end likewise } } if (t1 == null) { if (smileParser.nextToken() != null) { return jsonParser; } } jsonParser.close(); smileParser.close(); return null; } public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java ... [input-dir]"); System.exit(1); } new VerifySmileDocs().verifyAll(new File(args[0])); } } jackson-src-1.9.2/src/java/0000755000175000017500000000000011655120726016127 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/0000755000175000017500000000000011655120726016716 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/0000755000175000017500000000000011655120726020511 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/0000755000175000017500000000000011672662540022145 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/JsonEncoding.java0000644000175000017500000000272611655120726025373 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Enumeration that defines legal encodings that can be used * for JSON content, based on list of allowed encodings from * JSON specification. *

* Note: if application want to explicitly disregard Encoding * limitations (to read in JSON encoded using an encoding not * listed as allowed), they can use {@link java.io.Reader} / * {@link java.io.Writer} instances as input */ public enum JsonEncoding { UTF8("UTF-8", false), // N/A for big-endian, really UTF16_BE("UTF-16BE", true), UTF16_LE("UTF-16LE", false), UTF32_BE("UTF-32BE", true), UTF32_LE("UTF-32LE", false) ; protected final String _javaName; protected final boolean _bigEndian; JsonEncoding(String javaName, boolean bigEndian) { _javaName = javaName; _bigEndian = bigEndian; } /** * Method for accessing encoding name that JDK will support. * * @return Matching encoding name that JDK will support. */ public String getJavaName() { return _javaName; } /** * Whether encoding is big-endian (if encoding supports such * notion). If no such distinction is made (as is the case for * {@link #UTF8}), return value is undefined. * * @return True for big-endian encodings; false for little-endian * (or if not applicable) */ public boolean isBigEndian() { return _bigEndian; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonFactory.java0000644000175000017500000007701411655120726025256 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson; import java.io.*; import java.lang.ref.SoftReference; import java.net.URL; import org.codehaus.jackson.format.InputAccessor; import org.codehaus.jackson.format.MatchStrength; import org.codehaus.jackson.io.*; import org.codehaus.jackson.impl.ByteSourceBootstrapper; import org.codehaus.jackson.impl.ReaderBasedParser; import org.codehaus.jackson.impl.Utf8Generator; import org.codehaus.jackson.impl.WriterBasedGenerator; import org.codehaus.jackson.sym.BytesToNameCanonicalizer; import org.codehaus.jackson.sym.CharsToNameCanonicalizer; import org.codehaus.jackson.util.BufferRecycler; import org.codehaus.jackson.util.VersionUtil; /** * The main factory class of Jackson package, used to configure and * construct reader (aka parser, {@link JsonParser}) * and writer (aka generator, {@link JsonGenerator}) * instances. *

* Factory instances are thread-safe and reusable after configuration * (if any). Typically applications and services use only a single * globally shared factory instance, unless they need differently * configured factories. Factory reuse is important if efficiency matters; * most recycling of expensive construct is done on per-factory basis. *

* Creation of a factory instance is a light-weight operation, * and since there is no need for pluggable alternative implementations * (as there is no "standard" JSON processor API to implement), * the default constructor is used for constructing factory * instances. * * @author Tatu Saloranta */ public class JsonFactory implements Versioned { /** * Name used to identify JSON format * (and returned by {@link #getFormatName()} */ public final static String FORMAT_NAME_JSON = "JSON"; /** * Bitfield (set of flags) of all parser features that are enabled * by default. */ final static int DEFAULT_PARSER_FEATURE_FLAGS = JsonParser.Feature.collectDefaults(); /** * Bitfield (set of flags) of all generator features that are enabled * by default. */ final static int DEFAULT_GENERATOR_FEATURE_FLAGS = JsonGenerator.Feature.collectDefaults(); /* /********************************************************** /* Buffer, symbol table management /********************************************************** */ /** * This ThreadLocal contains a {@link java.lang.ref.SoftRerefence} * to a {@link BufferRecycler} used to provide a low-cost * buffer recycling between reader and writer instances. */ final protected static ThreadLocal> _recyclerRef = new ThreadLocal>(); /** * Each factory comes equipped with a shared root symbol table. * It should not be linked back to the original blueprint, to * avoid contents from leaking between factories. */ protected CharsToNameCanonicalizer _rootCharSymbols = CharsToNameCanonicalizer.createRoot(); /** * Alternative to the basic symbol table, some stream-based * parsers use different name canonicalization method. *

* TODO: should clean up this; looks messy having 2 alternatives * with not very clear differences. */ protected BytesToNameCanonicalizer _rootByteSymbols = BytesToNameCanonicalizer.createRoot(); /* /********************************************************** /* Configuration /********************************************************** */ /** * Object that implements conversion functionality between * Java objects and JSON content. For base JsonFactory implementation * usually not set by default, but can be explicitly set. * Sub-classes (like @link org.codehaus.jackson.map.MappingJsonFactory} * usually provide an implementation. */ protected ObjectCodec _objectCodec; /** * Currently enabled parser features. */ protected int _parserFeatures = DEFAULT_PARSER_FEATURE_FLAGS; /** * Currently enabled generator features. */ protected int _generatorFeatures = DEFAULT_GENERATOR_FEATURE_FLAGS; /** * Definition of custom character escapes to use for generators created * by this factory, if any. If null, standard data format specific * escapes are used. * * @since 1.8 */ protected CharacterEscapes _characterEscapes; /** * Optional helper object that may decorate input sources, to do * additional processing on input during parsing. * * @since 1.8 */ protected InputDecorator _inputDecorator; /** * Optional helper object that may decorate output object, to do * additional processing on output during content generation. * * @since 1.8 */ protected OutputDecorator _outputDecorator; /* /********************************************************** /* Construction /********************************************************** */ /** * Default constructor used to create factory instances. * Creation of a factory instance is a light-weight operation, * but it is still a good idea to reuse limited number of * factory instances (and quite often just a single instance): * factories are used as context for storing some reused * processing objects (such as symbol tables parsers use) * and this reuse only works within context of a single * factory instance. */ public JsonFactory() { this(null); } public JsonFactory(ObjectCodec oc) { _objectCodec = oc; } /* /********************************************************** /* Format detection functionality (since 1.8) /********************************************************** */ /** * Method that returns short textual id identifying format * this factory supports. *

* Note: sub-classes should override this method; default * implementation will return null for all sub-classes * * @since 1.8 */ public String getFormatName() { /* Somewhat nasty check: since we can't make this abstract * (due to backwards compatibility concerns), need to prevent * format name "leakage" */ if (getClass() == JsonFactory.class) { return FORMAT_NAME_JSON; } return null; } public MatchStrength hasFormat(InputAccessor acc) throws IOException { // since we can't keep this abstract, only implement for "vanilla" instance if (getClass() == JsonFactory.class) { return hasJSONFormat(acc); } return null; } protected MatchStrength hasJSONFormat(InputAccessor acc) throws IOException { return ByteSourceBootstrapper.hasJSONFormat(acc); } /* /********************************************************** /* Versioned /********************************************************** */ @Override public Version version() { // VERSION is included under impl, so can't pass this class: return VersionUtil.versionFor(Utf8Generator.class); } /* /********************************************************** /* Configuration, parser settings /********************************************************** */ /** * Method for enabling or disabling specified parser feature * (check {@link JsonParser.Feature} for list of features) * * @since 1.2 */ public final JsonFactory configure(JsonParser.Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; } /** * Method for enabling specified parser feature * (check {@link JsonParser.Feature} for list of features) * * @since 1.2 */ public JsonFactory enable(JsonParser.Feature f) { _parserFeatures |= f.getMask(); return this; } /** * Method for disabling specified parser features * (check {@link JsonParser.Feature} for list of features) * * @since 1.2 */ public JsonFactory disable(JsonParser.Feature f) { _parserFeatures &= ~f.getMask(); return this; } /** * Checked whether specified parser feature is enabled. * * @since 1.2 */ public final boolean isEnabled(JsonParser.Feature f) { return (_parserFeatures & f.getMask()) != 0; } // // // Older deprecated (as of 1.2) methods /** * @deprecated Use {@link #enable(JsonParser.Feature)} instead */ @SuppressWarnings("dep-ann") public final void enableParserFeature(JsonParser.Feature f) { enable(f); } /** * @deprecated Use {@link #disable(JsonParser.Feature)} instead */ @SuppressWarnings("dep-ann") public final void disableParserFeature(JsonParser.Feature f) { disable(f); } /** * @deprecated Use {@link #configure(JsonParser.Feature, boolean)} instead */ @SuppressWarnings("dep-ann") public final void setParserFeature(JsonParser.Feature f, boolean state) { configure(f, state); } /** * @deprecated Use {@link #isEnabled(JsonParser.Feature)} instead */ @SuppressWarnings("dep-ann") public final boolean isParserFeatureEnabled(JsonParser.Feature f) { return (_parserFeatures & f.getMask()) != 0; } /** * Method for getting currently configured input decorator (if any; * there is no default decorator). * * @since 1.8 */ public InputDecorator getInputDecorator() { return _inputDecorator; } /** * Method for overriding currently configured input decorator * * @since 1.8 */ public JsonFactory setInputDecorator(InputDecorator d) { _inputDecorator = d; return this; } /* /********************************************************** /* Configuration, generator settings /********************************************************** */ /** * Method for enabling or disabling specified generator feature * (check {@link JsonGenerator.Feature} for list of features) * * @since 1.2 */ public final JsonFactory configure(JsonGenerator.Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; } /** * Method for enabling specified generator features * (check {@link JsonGenerator.Feature} for list of features) * * @since 1.2 */ public JsonFactory enable(JsonGenerator.Feature f) { _generatorFeatures |= f.getMask(); return this; } /** * Method for disabling specified generator feature * (check {@link JsonGenerator.Feature} for list of features) * * @since 1.2 */ public JsonFactory disable(JsonGenerator.Feature f) { _generatorFeatures &= ~f.getMask(); return this; } /** * Check whether specified generator feature is enabled. * * @since 1.2 */ public final boolean isEnabled(JsonGenerator.Feature f) { return (_generatorFeatures & f.getMask()) != 0; } // // // Older deprecated (as of 1.2) methods /** * @deprecated Use {@link #enable(JsonGenerator.Feature)} instead */ @Deprecated public final void enableGeneratorFeature(JsonGenerator.Feature f) { enable(f); } /** * @deprecated Use {@link #disable(JsonGenerator.Feature)} instead */ @Deprecated public final void disableGeneratorFeature(JsonGenerator.Feature f) { disable(f); } /** * @deprecated Use {@link #configure(JsonGenerator.Feature, boolean)} instead */ @Deprecated public final void setGeneratorFeature(JsonGenerator.Feature f, boolean state) { configure(f, state); } /** * @deprecated Use {@link #isEnabled(JsonGenerator.Feature)} instead */ @Deprecated public final boolean isGeneratorFeatureEnabled(JsonGenerator.Feature f) { return isEnabled(f); } /** * Method for accessing custom escapes factory uses for {@link JsonGenerator}s * it creates. * * @since 1.8 */ public CharacterEscapes getCharacterEscapes() { return _characterEscapes; } /** * Method for defining custom escapes factory uses for {@link JsonGenerator}s * it creates. * * @since 1.8 */ public JsonFactory setCharacterEscapes(CharacterEscapes esc) { _characterEscapes = esc; return this; } /** * Method for getting currently configured output decorator (if any; * there is no default decorator). * * @since 1.8 */ public OutputDecorator getOutputDecorator() { return _outputDecorator; } /** * Method for overriding currently configured output decorator * * @since 1.8 */ public JsonFactory setOutputDecorator(OutputDecorator d) { _outputDecorator = d; return this; } /* /********************************************************** /* Configuration, other /********************************************************** */ /** * Method for associating a {@link ObjectCodec} (typically * a {@link org.codehaus.jackson.map.ObjectMapper}) with * this factory (and more importantly, parsers and generators * it constructs). This is needed to use data-binding methods * of {@link JsonParser} and {@link JsonGenerator} instances. */ public JsonFactory setCodec(ObjectCodec oc) { _objectCodec = oc; return this; } public ObjectCodec getCodec() { return _objectCodec; } /* /********************************************************** /* Reader factories /********************************************************** */ /** * Method for constructing JSON parser instance to parse * contents of specified file. Encoding is auto-detected * from contents according to JSON specification recommended * mechanism. *

* Underlying input stream (needed for reading contents) * will be owned (and managed, i.e. closed as need be) by * the parser, since caller has no access to it. * * @param f File that contains JSON content to parse */ public JsonParser createJsonParser(File f) throws IOException, JsonParseException { // true, since we create InputStream from File IOContext ctxt = _createContext(f, true); InputStream in = new FileInputStream(f); // [JACKSON-512]: allow wrapping with InputDecorator if (_inputDecorator != null) { in = _inputDecorator.decorate(ctxt, in); } return _createJsonParser(in, ctxt); } /** * Method for constructing JSON parser instance to parse * contents of resource reference by given URL. * Encoding is auto-detected * from contents according to JSON specification recommended * mechanism. *

* Underlying input stream (needed for reading contents) * will be owned (and managed, i.e. closed as need be) by * the parser, since caller has no access to it. * * @param url URL pointing to resource that contains JSON content to parse */ public JsonParser createJsonParser(URL url) throws IOException, JsonParseException { // true, since we create InputStream from URL IOContext ctxt = _createContext(url, true); InputStream in = _optimizedStreamFromURL(url); // [JACKSON-512]: allow wrapping with InputDecorator if (_inputDecorator != null) { in = _inputDecorator.decorate(ctxt, in); } return _createJsonParser(in, ctxt); } /** * Method for constructing JSON parser instance to parse * the contents accessed via specified input stream. *

* The input stream will not be owned by * the parser, it will still be managed (i.e. closed if * end-of-stream is reacher, or parser close method called) * if (and only if) {@link org.codehaus.jackson.JsonParser.Feature#AUTO_CLOSE_SOURCE} * is enabled. *

* Note: no encoding argument is taken since it can always be * auto-detected as suggested by Json RFC. * * @param in InputStream to use for reading JSON content to parse */ public JsonParser createJsonParser(InputStream in) throws IOException, JsonParseException { IOContext ctxt = _createContext(in, false); // [JACKSON-512]: allow wrapping with InputDecorator if (_inputDecorator != null) { in = _inputDecorator.decorate(ctxt, in); } return _createJsonParser(in, ctxt); } /** * Method for constructing parser for parsing * the contents accessed via specified Reader.

* The read stream will not be owned by * the parser, it will still be managed (i.e. closed if * end-of-stream is reacher, or parser close method called) * if (and only if) {@link org.codehaus.jackson.JsonParser.Feature#AUTO_CLOSE_SOURCE} * is enabled. *

* * @param r Reader to use for reading JSON content to parse */ public JsonParser createJsonParser(Reader r) throws IOException, JsonParseException { // false -> we do NOT own Reader (did not create it) IOContext ctxt = _createContext(r, false); // [JACKSON-512]: allow wrapping with InputDecorator if (_inputDecorator != null) { r = _inputDecorator.decorate(ctxt, r); } return _createJsonParser(r, ctxt); } /** * Method for constructing parser for parsing * the contents of given byte array. */ public JsonParser createJsonParser(byte[] data) throws IOException, JsonParseException { IOContext ctxt = _createContext(data, true); // [JACKSON-512]: allow wrapping with InputDecorator if (_inputDecorator != null) { InputStream in = _inputDecorator.decorate(ctxt, data, 0, data.length); if (in != null) { return _createJsonParser(in, ctxt); } } return _createJsonParser(data, 0, data.length, ctxt); } /** * Method for constructing parser for parsing * the contents of given byte array. * * @param data Buffer that contains data to parse * @param offset Offset of the first data byte within buffer * @param len Length of contents to parse within buffer */ public JsonParser createJsonParser(byte[] data, int offset, int len) throws IOException, JsonParseException { IOContext ctxt = _createContext(data, true); // [JACKSON-512]: allow wrapping with InputDecorator if (_inputDecorator != null) { InputStream in = _inputDecorator.decorate(ctxt, data, offset, len); if (in != null) { return _createJsonParser(in, ctxt); } } return _createJsonParser(data, offset, len, ctxt); } /** * Method for constructing parser for parsing * contens of given String. */ public JsonParser createJsonParser(String content) throws IOException, JsonParseException { Reader r = new StringReader(content); // true -> we own the Reader (and must close); not a big deal IOContext ctxt = _createContext(r, true); // [JACKSON-512]: allow wrapping with InputDecorator if (_inputDecorator != null) { r = _inputDecorator.decorate(ctxt, r); } return _createJsonParser(r, ctxt); } /* /********************************************************** /* Generator factories /********************************************************** */ /** * Method for constructing JSON generator for writing JSON content * using specified output stream. * Encoding to use must be specified, and needs to be one of available * types (as per JSON specification). *

* Underlying stream is NOT owned by the generator constructed, * so that generator will NOT close the output stream when * {@link JsonGenerator#close} is called (unless auto-closing * feature, * {@link org.codehaus.jackson.JsonGenerator.Feature#AUTO_CLOSE_TARGET} * is enabled). * Using application needs to close it explicitly if this is the case. *

* Note: there are formats that use fixed encoding (like most binary data formats) * and that ignore passed in encoding. * * @param out OutputStream to use for writing JSON content * @param enc Character encoding to use */ public JsonGenerator createJsonGenerator(OutputStream out, JsonEncoding enc) throws IOException { // false -> we won't manage the stream unless explicitly directed to IOContext ctxt = _createContext(out, false); ctxt.setEncoding(enc); if (enc == JsonEncoding.UTF8) { // [JACKSON-512]: allow wrapping with _outputDecorator if (_outputDecorator != null) { out = _outputDecorator.decorate(ctxt, out); } return _createUTF8JsonGenerator(out, ctxt); } Writer w = _createWriter(out, enc, ctxt); // [JACKSON-512]: allow wrapping with _outputDecorator if (_outputDecorator != null) { w = _outputDecorator.decorate(ctxt, w); } return _createJsonGenerator(w, ctxt); } /** * Method for constructing JSON generator for writing JSON content * using specified Writer. *

* Underlying stream is NOT owned by the generator constructed, * so that generator will NOT close the Reader when * {@link JsonGenerator#close} is called (unless auto-closing * feature, * {@link org.codehaus.jackson.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). * Using application needs to close it explicitly. * * @param out Writer to use for writing JSON content */ public JsonGenerator createJsonGenerator(Writer out) throws IOException { IOContext ctxt = _createContext(out, false); // [JACKSON-512]: allow wrapping with _outputDecorator if (_outputDecorator != null) { out = _outputDecorator.decorate(ctxt, out); } return _createJsonGenerator(out, ctxt); } /** * Convenience method for constructing generator that uses default * encoding of the format (UTF-8 for JSON and most other data formats). *

* Note: there are formats that use fixed encoding (like most binary data formats). * * @since 1.8 */ public JsonGenerator createJsonGenerator(OutputStream out) throws IOException { return createJsonGenerator(out, JsonEncoding.UTF8); } /** * Method for constructing JSON generator for writing JSON content * to specified file, overwriting contents it might have (or creating * it if such file does not yet exist). * Encoding to use must be specified, and needs to be one of available * types (as per JSON specification). *

* Underlying stream is owned by the generator constructed, * i.e. generator will handle closing of file when * {@link JsonGenerator#close} is called. * * @param f File to write contents to * @param enc Character encoding to use */ public JsonGenerator createJsonGenerator(File f, JsonEncoding enc) throws IOException { OutputStream out = new FileOutputStream(f); // true -> yes, we have to manage the stream since we created it IOContext ctxt = _createContext(out, true); ctxt.setEncoding(enc); if (enc == JsonEncoding.UTF8) { // [JACKSON-512]: allow wrapping with _outputDecorator if (_outputDecorator != null) { out = _outputDecorator.decorate(ctxt, out); } return _createUTF8JsonGenerator(out, ctxt); } Writer w = _createWriter(out, enc, ctxt); // [JACKSON-512]: allow wrapping with _outputDecorator if (_outputDecorator != null) { w = _outputDecorator.decorate(ctxt, w); } return _createJsonGenerator(w, ctxt); } /* /********************************************************** /* Factory methods used by factory for creating parser instances, /* overridable by sub-classes /********************************************************** */ /** * Overridable factory method that actually instantiates desired parser * given {@link InputStream} and context object. *

* This method is specifically designed to remain * compatible between minor versions so that sub-classes can count * on it being called as expected. That is, it is part of official * interface from sub-class perspective, although not a public * method available to users of factory implementations. */ protected JsonParser _createJsonParser(InputStream in, IOContext ctxt) throws IOException, JsonParseException { return new ByteSourceBootstrapper(ctxt, in).constructParser(_parserFeatures, _objectCodec, _rootByteSymbols, _rootCharSymbols); } /** * Overridable factory method that actually instantiates parser * using given {@link Reader} object for reading content. *

* This method is specifically designed to remain * compatible between minor versions so that sub-classes can count * on it being called as expected. That is, it is part of official * interface from sub-class perspective, although not a public * method available to users of factory implementations. */ protected JsonParser _createJsonParser(Reader r, IOContext ctxt) throws IOException, JsonParseException { return new ReaderBasedParser(ctxt, _parserFeatures, r, _objectCodec, _rootCharSymbols.makeChild(isEnabled(JsonParser.Feature.CANONICALIZE_FIELD_NAMES), isEnabled(JsonParser.Feature.INTERN_FIELD_NAMES))); } /** * Overridable factory method that actually instantiates parser * using given {@link Reader} object for reading content * passed as raw byte array. *

* This method is specifically designed to remain * compatible between minor versions so that sub-classes can count * on it being called as expected. That is, it is part of official * interface from sub-class perspective, although not a public * method available to users of factory implementations. */ protected JsonParser _createJsonParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException, JsonParseException { return new ByteSourceBootstrapper(ctxt, data, offset, len).constructParser(_parserFeatures, _objectCodec, _rootByteSymbols, _rootCharSymbols); } /* /********************************************************** /* Factory methods used by factory for creating generator instances, /* overridable by sub-classes /********************************************************** */ /** * Overridable factory method that actually instantiates generator for * given {@link Writer} and context object. *

* This method is specifically designed to remain * compatible between minor versions so that sub-classes can count * on it being called as expected. That is, it is part of official * interface from sub-class perspective, although not a public * method available to users of factory implementations. */ protected JsonGenerator _createJsonGenerator(Writer out, IOContext ctxt) throws IOException { WriterBasedGenerator gen = new WriterBasedGenerator(ctxt, _generatorFeatures, _objectCodec, out); if (_characterEscapes != null) { gen.setCharacterEscapes(_characterEscapes); } return gen; } /** * Overridable factory method that actually instantiates generator for * given {@link OutputStream} and context object, using UTF-8 encoding. *

* This method is specifically designed to remain * compatible between minor versions so that sub-classes can count * on it being called as expected. That is, it is part of official * interface from sub-class perspective, although not a public * method available to users of factory implementations. */ protected JsonGenerator _createUTF8JsonGenerator(OutputStream out, IOContext ctxt) throws IOException { Utf8Generator gen = new Utf8Generator(ctxt, _generatorFeatures, _objectCodec, out); if (_characterEscapes != null) { gen.setCharacterEscapes(_characterEscapes); } return gen; } protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException { // note: this should not get called any more (caller checks, dispatches) if (enc == JsonEncoding.UTF8) { // We have optimized writer for UTF-8 return new UTF8Writer(ctxt, out); } // not optimal, but should do unless we really care about UTF-16/32 encoding speed return new OutputStreamWriter(out, enc.getJavaName()); } /* /********************************************************** /* Internal factory methods, other /********************************************************** */ /** * Overridable factory method that actually instantiates desired * context object. */ protected IOContext _createContext(Object srcRef, boolean resourceManaged) { return new IOContext(_getBufferRecycler(), srcRef, resourceManaged); } /** * Method used by factory to create buffer recycler instances * for parsers and generators. *

* Note: only public to give access for ObjectMapper */ public BufferRecycler _getBufferRecycler() { SoftReference ref = _recyclerRef.get(); BufferRecycler br = (ref == null) ? null : ref.get(); if (br == null) { br = new BufferRecycler(); _recyclerRef.set(new SoftReference(br)); } return br; } /** * Helper methods used for constructing an optimal stream for * parsers to use, when input is to be read from an URL. * This helps when reading file content via URL. */ protected InputStream _optimizedStreamFromURL(URL url) throws IOException { if ("file".equals(url.getProtocol())) { /* Can not do this if the path refers * to a network drive on windows. This fixes the problem; * might not be needed on all platforms (NFS?), but should not * matter a lot: performance penalty of extra wrapping is more * relevant when accessing local file system. */ String host = url.getHost(); if (host == null || host.length() == 0) { return new FileInputStream(url.getPath()); } } return url.openStream(); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonParseException.java0000644000175000017500000000106011655120726026564 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Exception type for parsing problems, used when non-well-formed content * (content that does not conform to JSON syntax as per specification) * is encountered. */ public class JsonParseException extends JsonProcessingException { final static long serialVersionUID = 123; // Stupid eclipse... public JsonParseException(String msg, JsonLocation loc) { super(msg, loc); } public JsonParseException(String msg, JsonLocation loc, Throwable root) { super(msg, loc, root); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonGenerationException.java0000644000175000017500000000124611655120726027613 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Exception type for exceptions during JSON writing, such as trying * to output content in wrong context (non-matching end-array or end-object, * for example). */ public class JsonGenerationException extends JsonProcessingException { final static long serialVersionUID = 123; // Stupid eclipse... public JsonGenerationException(Throwable rootCause) { super(rootCause); } public JsonGenerationException(String msg) { super(msg, (JsonLocation)null); } public JsonGenerationException(String msg, Throwable rootCause) { super(msg, (JsonLocation)null, rootCause); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/0000755000175000017500000000000011672662540023106 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/impl/JsonGeneratorBase.java0000644000175000017500000004252711655120726027332 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.codehaus.jackson.*; import org.codehaus.jackson.util.DefaultPrettyPrinter; import org.codehaus.jackson.util.VersionUtil; /** * This base class implements part of API that a JSON generator exposes * to applications, adds shared internal methods that sub-classes * can use and adds some abstract methods sub-classes must implement. */ public abstract class JsonGeneratorBase extends JsonGenerator { /* /********************************************************** /* Configuration /********************************************************** */ protected ObjectCodec _objectCodec; /** * Bit flag composed of bits that indicate which * {@link org.codehaus.jackson.JsonGenerator.Feature}s * are enabled. */ protected int _features; /** * Flag set to indicate that implicit conversion from number * to JSON String is needed (as per * {@link org.codehaus.jackson.JsonGenerator.Feature#WRITE_NUMBERS_AS_STRINGS}). */ protected boolean _cfgNumbersAsStrings; /* /********************************************************** /* State /********************************************************** */ /** * Object that keeps track of the current contextual state * of the generator. */ protected JsonWriteContext _writeContext; /** * Flag that indicates whether generator is closed or not. Gets * set when it is closed by an explicit call * ({@link #close}). */ protected boolean _closed; /* /********************************************************** /* Life-cycle /********************************************************** */ protected JsonGeneratorBase(int features, ObjectCodec codec) { super(); _features = features; _writeContext = JsonWriteContext.createRootContext(); _objectCodec = codec; _cfgNumbersAsStrings = isEnabled(Feature.WRITE_NUMBERS_AS_STRINGS); } @Override public Version version() { return VersionUtil.versionFor(getClass()); } /* /********************************************************** /* Configuration /********************************************************** */ @Override public JsonGenerator enable(Feature f) { _features |= f.getMask(); if (f == Feature.WRITE_NUMBERS_AS_STRINGS) { _cfgNumbersAsStrings = true; } else if (f == Feature.ESCAPE_NON_ASCII) { setHighestNonEscapedChar(127); } return this; } @Override public JsonGenerator disable(Feature f) { _features &= ~f.getMask(); if (f == Feature.WRITE_NUMBERS_AS_STRINGS) { _cfgNumbersAsStrings = false; } else if (f == Feature.ESCAPE_NON_ASCII) { setHighestNonEscapedChar(0); } return this; } //public JsonGenerator configure(Feature f, boolean state) { } @Override public final boolean isEnabled(Feature f) { return (_features & f.getMask()) != 0; } @Override public JsonGenerator useDefaultPrettyPrinter() { return setPrettyPrinter(new DefaultPrettyPrinter()); } @Override public JsonGenerator setCodec(ObjectCodec oc) { _objectCodec = oc; return this; } @Override public final ObjectCodec getCodec() { return _objectCodec; } /* /********************************************************** /* Public API, accessors /********************************************************** */ /** * Note: co-variant return type. */ @Override public final JsonWriteContext getOutputContext() { return _writeContext; } /* /********************************************************** /* Public API, write methods, structural /********************************************************** */ @Override public void writeStartArray() throws IOException, JsonGenerationException { // Array is a value, need to verify it's allowed _verifyValueWrite("start an array"); _writeContext = _writeContext.createChildArrayContext(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeStartArray(this); } else { _writeStartArray(); } } /** * @deprecated since 1.7, should just override {@link #writeStartArray} instead * of defining this method */ @Deprecated protected void _writeStartArray() throws IOException, JsonGenerationException { } @Override public void writeEndArray() throws IOException, JsonGenerationException { if (!_writeContext.inArray()) { _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc()); } if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount()); } else { _writeEndArray(); } _writeContext = _writeContext.getParent(); } /** * @deprecated since 1.7, should just override {@link #writeEndArray} instead * of defining this method */ @Deprecated protected void _writeEndArray() throws IOException, JsonGenerationException { } @Override public void writeStartObject() throws IOException, JsonGenerationException { _verifyValueWrite("start an object"); _writeContext = _writeContext.createChildObjectContext(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeStartObject(this); } else { _writeStartObject(); } } /** * @deprecated since 1.7, should just override {@link #writeStartObject} instead * of defining this method */ @Deprecated protected void _writeStartObject() throws IOException, JsonGenerationException { } @Override public void writeEndObject() throws IOException, JsonGenerationException { if (!_writeContext.inObject()) { _reportError("Current context not an object but "+_writeContext.getTypeDesc()); } _writeContext = _writeContext.getParent(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount()); } else { _writeEndObject(); } } /** * @deprecated since 1.7, should just override {@link #writeEndObject} instead * of defining this method */ @Deprecated protected void _writeEndObject() throws IOException, JsonGenerationException { } /* /********************************************************** /* Public API, write methods, textual /********************************************************** */ //public abstract void writeString(String text) throws IOException, JsonGenerationException; //public abstract void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException; //public abstract void writeRaw(String text) throws IOException, JsonGenerationException; //public abstract void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException; @Override public void writeRawValue(String text) throws IOException, JsonGenerationException { _verifyValueWrite("write raw value"); writeRaw(text); } @Override public void writeRawValue(String text, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write raw value"); writeRaw(text, offset, len); } @Override public void writeRawValue(char[] text, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write raw value"); writeRaw(text, offset, len); } //public abstract void writeBinary(byte[] data, int offset, int len, boolean includeLFs) throws IOException, JsonGenerationException; /* /********************************************************** /* Public API, write methods, primitive /********************************************************** */ // Not implemented at this level, added as placeholders /* public abstract void writeNumber(int i) public abstract void writeNumber(long l) public abstract void writeNumber(double d) public abstract void writeNumber(float f) public abstract void writeNumber(BigDecimal dec) public abstract void writeBoolean(boolean state) public abstract void writeNull() */ /* /********************************************************** /* Public API, write methods, POJOs, trees /********************************************************** */ @Override public void writeObject(Object value) throws IOException, JsonProcessingException { if (value == null) { // important: call method that does check value write: writeNull(); } else { /* 02-Mar-2009, tatu: we are NOT to call _verifyValueWrite here, * because that will be done when codec actually serializes * contained POJO. If we did call it it would advance state * causing exception later on */ if (_objectCodec != null) { _objectCodec.writeValue(this, value); return; } _writeSimpleObject(value); } } @Override public void writeTree(JsonNode rootNode) throws IOException, JsonProcessingException { // As with 'writeObject()', we are not check if write would work if (rootNode == null) { writeNull(); } else { if (_objectCodec == null) { throw new IllegalStateException("No ObjectCodec defined for the generator, can not serialize JsonNode-based trees"); } _objectCodec.writeTree(this, rootNode); } } /* /********************************************************** /* Public API, low-level output handling /********************************************************** */ @Override public abstract void flush() throws IOException; @Override public void close() throws IOException { _closed = true; } @Override public boolean isClosed() { return _closed; } /* /********************************************************** /* Public API, copy-through methods /********************************************************** */ @Override public final void copyCurrentEvent(JsonParser jp) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); // sanity check; what to do? if (t == null) { _reportError("No current event to copy"); } switch(t) { case START_OBJECT: writeStartObject(); break; case END_OBJECT: writeEndObject(); break; case START_ARRAY: writeStartArray(); break; case END_ARRAY: writeEndArray(); break; case FIELD_NAME: writeFieldName(jp.getCurrentName()); break; case VALUE_STRING: if (jp.hasTextCharacters()) { writeString(jp.getTextCharacters(), jp.getTextOffset(), jp.getTextLength()); } else { writeString(jp.getText()); } break; case VALUE_NUMBER_INT: switch (jp.getNumberType()) { case INT: writeNumber(jp.getIntValue()); break; case BIG_INTEGER: writeNumber(jp.getBigIntegerValue()); break; default: writeNumber(jp.getLongValue()); } break; case VALUE_NUMBER_FLOAT: switch (jp.getNumberType()) { case BIG_DECIMAL: writeNumber(jp.getDecimalValue()); break; case FLOAT: writeNumber(jp.getFloatValue()); break; default: writeNumber(jp.getDoubleValue()); } break; case VALUE_TRUE: writeBoolean(true); break; case VALUE_FALSE: writeBoolean(false); break; case VALUE_NULL: writeNull(); break; case VALUE_EMBEDDED_OBJECT: writeObject(jp.getEmbeddedObject()); break; default: _cantHappen(); } } @Override public final void copyCurrentStructure(JsonParser jp) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); // Let's handle field-name separately first if (t == JsonToken.FIELD_NAME) { writeFieldName(jp.getCurrentName()); t = jp.nextToken(); // fall-through to copy the associated value } switch (t) { case START_ARRAY: writeStartArray(); while (jp.nextToken() != JsonToken.END_ARRAY) { copyCurrentStructure(jp); } writeEndArray(); break; case START_OBJECT: writeStartObject(); while (jp.nextToken() != JsonToken.END_OBJECT) { copyCurrentStructure(jp); } writeEndObject(); break; default: // others are simple: copyCurrentEvent(jp); } } /* /********************************************************** /* Package methods for this, sub-classes /********************************************************** */ protected abstract void _releaseBuffers(); protected abstract void _verifyValueWrite(String typeMsg) throws IOException, JsonGenerationException; protected void _reportError(String msg) throws JsonGenerationException { throw new JsonGenerationException(msg); } protected void _cantHappen() { throw new RuntimeException("Internal error: should never end up through this code path"); } /** * Helper method to try to call appropriate write method for given * untyped Object. At this point, no structural conversions should be done, * only simple basic types are to be coerced as necessary. * * @param value Non-null value to write */ protected void _writeSimpleObject(Object value) throws IOException, JsonGenerationException { /* 31-Dec-2009, tatu: Actually, we could just handle some basic * types even without codec. This can improve interoperability, * and specifically help with TokenBuffer. */ if (value == null) { writeNull(); return; } if (value instanceof String) { writeString((String) value); return; } if (value instanceof Number) { Number n = (Number) value; if (n instanceof Integer) { writeNumber(n.intValue()); return; } else if (n instanceof Long) { writeNumber(n.longValue()); return; } else if (n instanceof Double) { writeNumber(n.doubleValue()); return; } else if (n instanceof Float) { writeNumber(n.floatValue()); return; } else if (n instanceof Short) { writeNumber(n.shortValue()); return; } else if (n instanceof Byte) { writeNumber(n.byteValue()); return; } else if (n instanceof BigInteger) { writeNumber((BigInteger) n); return; } else if (n instanceof BigDecimal) { writeNumber((BigDecimal) n); return; // then Atomic types } else if (n instanceof AtomicInteger) { writeNumber(((AtomicInteger) n).get()); return; } else if (n instanceof AtomicLong) { writeNumber(((AtomicLong) n).get()); return; } } else if (value instanceof byte[]) { writeBinary((byte[]) value); return; } else if (value instanceof Boolean) { writeBoolean(((Boolean) value).booleanValue()); return; } else if (value instanceof AtomicBoolean) { writeBoolean(((AtomicBoolean) value).get()); return; } throw new IllegalStateException("No ObjectCodec defined for the generator, can only serialize simple wrapper types (type passed " +value.getClass().getName()+")"); } protected final void _throwInternal() { throw new RuntimeException("Internal error: this code path should never get executed"); } /** * @since 1.7 */ protected void _reportUnsupportedOperation() { throw new UnsupportedOperationException("Operation not supported by generator of type "+getClass().getName()); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/Utf8Generator.java0000644000175000017500000016707011655120726026455 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.io.CharacterEscapes; import org.codehaus.jackson.io.IOContext; import org.codehaus.jackson.io.NumberOutput; import org.codehaus.jackson.io.SerializedString; import org.codehaus.jackson.util.CharTypes; public class Utf8Generator extends JsonGeneratorBase { private final static byte BYTE_u = (byte) 'u'; private final static byte BYTE_0 = (byte) '0'; private final static byte BYTE_LBRACKET = (byte) '['; private final static byte BYTE_RBRACKET = (byte) ']'; private final static byte BYTE_LCURLY = (byte) '{'; private final static byte BYTE_RCURLY = (byte) '}'; private final static byte BYTE_BACKSLASH = (byte) '\\'; private final static byte BYTE_SPACE = (byte) ' '; private final static byte BYTE_COMMA = (byte) ','; private final static byte BYTE_COLON = (byte) ':'; private final static byte BYTE_QUOTE = (byte) '"'; protected final static int SURR1_FIRST = 0xD800; protected final static int SURR1_LAST = 0xDBFF; protected final static int SURR2_FIRST = 0xDC00; protected final static int SURR2_LAST = 0xDFFF; // intermediate copies only made up to certain length... private final static int MAX_BYTES_TO_BUFFER = 512; final static byte[] HEX_CHARS = CharTypes.copyHexBytes(); private final static byte[] NULL_BYTES = { 'n', 'u', 'l', 'l' }; private final static byte[] TRUE_BYTES = { 't', 'r', 'u', 'e' }; private final static byte[] FALSE_BYTES = { 'f', 'a', 'l', 's', 'e' }; /** * This is the default set of escape codes, over 7-bit ASCII range * (first 128 character codes), used for single-byte UTF-8 characters. */ protected final static int[] sOutputEscapes = CharTypes.get7BitOutputEscapes(); /* /********************************************************** /* Configuration, basic I/O /********************************************************** */ final protected IOContext _ioContext; /** * Underlying output stream used for writing JSON content. */ final protected OutputStream _outputStream; /* /********************************************************** /* Configuration, output escaping /********************************************************** */ /** * Currently active set of output escape code definitions (whether * and how to escape or not) for 7-bit ASCII range (first 128 * character codes). Defined separately to make potentially * customizable */ protected int[] _outputEscapes = sOutputEscapes; /** * Value between 128 (0x80) and 65535 (0xFFFF) that indicates highest * Unicode code point that will not need escaping; or 0 to indicate * that all characters can be represented without escaping. * Typically used to force escaping of some portion of character set; * for example to always escape non-ASCII characters (if value was 127). *

* NOTE: not all sub-classes make use of this setting. */ protected int _maximumNonEscapedChar; /** * Definition of custom character escapes to use for generators created * by this factory, if any. If null, standard data format specific * escapes are used. * * @since 1.8 */ protected CharacterEscapes _characterEscapes; /* /********************************************************** /* Output buffering /********************************************************** */ /** * Intermediate buffer in which contents are buffered before * being written using {@link #_outputStream}. */ protected byte[] _outputBuffer; /** * Pointer to the position right beyond the last character to output * (end marker; may be past the buffer) */ protected int _outputTail = 0; /** * End marker of the output buffer; one past the last valid position * within the buffer. */ protected final int _outputEnd; /** * Maximum number of chars that we know will always fit * in the output buffer after escaping */ protected final int _outputMaxContiguous; /** * Intermediate buffer in which characters of a String are copied * before being encoded. */ protected char[] _charBuffer; /** * Length of _charBuffer */ protected final int _charBufferLength; /** * 6 character temporary buffer allocated if needed, for constructing * escape sequences */ protected byte[] _entityBuffer; /** * Flag that indicates whether the output buffer is recycable (and * needs to be returned to recycler once we are done) or not. */ protected boolean _bufferRecyclable; /* /********************************************************** /* Life-cycle /********************************************************** */ public Utf8Generator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out) { super(features, codec); _ioContext = ctxt; _outputStream = out; _bufferRecyclable = true; _outputBuffer = ctxt.allocWriteEncodingBuffer(); _outputEnd = _outputBuffer.length; /* To be exact, each char can take up to 6 bytes when escaped (Unicode * escape with backslash, 'u' and 4 hex digits); but to avoid fluctuation, * we will actually round down to only do up to 1/8 number of chars */ _outputMaxContiguous = _outputEnd >> 3; _charBuffer = ctxt.allocConcatBuffer(); _charBufferLength = _charBuffer.length; // By default we use this feature to determine additional quoting if (isEnabled(Feature.ESCAPE_NON_ASCII)) { setHighestNonEscapedChar(127); } } public Utf8Generator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out, byte[] outputBuffer, int outputOffset, boolean bufferRecyclable) { super(features, codec); _ioContext = ctxt; _outputStream = out; _bufferRecyclable = bufferRecyclable; _outputTail = outputOffset; _outputBuffer = outputBuffer; _outputEnd = _outputBuffer.length; // up to 6 bytes per char (see above), rounded up to 1/8 _outputMaxContiguous = _outputEnd >> 3; _charBuffer = ctxt.allocConcatBuffer(); _charBufferLength = _charBuffer.length; if (isEnabled(Feature.ESCAPE_NON_ASCII)) { setHighestNonEscapedChar(127); } } /* /********************************************************** /* Overridden configuration methods /********************************************************** */ @Override public JsonGenerator setHighestNonEscapedChar(int charCode) { _maximumNonEscapedChar = (charCode < 0) ? 0 : charCode; return this; } @Override public int getHighestEscapedChar() { return _maximumNonEscapedChar; } @Override public JsonGenerator setCharacterEscapes(CharacterEscapes esc) { _characterEscapes = esc; if (esc == null) { // revert to standard escapes _outputEscapes = sOutputEscapes; } else { _outputEscapes = esc.getEscapeCodesForAscii(); } return this; } /** * Method for accessing custom escapes factory uses for {@link JsonGenerator}s * it creates. * * @since 1.8 */ @Override public CharacterEscapes getCharacterEscapes() { return _characterEscapes; } @Override public Object getOutputTarget() { return _outputStream; } /* /********************************************************** /* Overridden methods /********************************************************** */ /* Most overrides in this section are just to make methods final, * to allow better inlining... */ @Override public final void writeStringField(String fieldName, String value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeString(value); } @Override public final void writeFieldName(String name) throws IOException, JsonGenerationException { int status = _writeContext.writeFieldName(name); if (status == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } if (_cfgPrettyPrinter != null) { _writePPFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA)); return; } if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) { // need comma if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_COMMA; } _writeFieldName(name); } @Override public final void writeFieldName(SerializedString name) throws IOException, JsonGenerationException { // Object is a value, need to verify it's allowed int status = _writeContext.writeFieldName(name.getValue()); if (status == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } if (_cfgPrettyPrinter != null) { _writePPFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA)); return; } if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_COMMA; } _writeFieldName(name); } @Override public final void writeFieldName(SerializableString name) throws IOException, JsonGenerationException { // Object is a value, need to verify it's allowed int status = _writeContext.writeFieldName(name.getValue()); if (status == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } if (_cfgPrettyPrinter != null) { _writePPFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA)); return; } if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_COMMA; } _writeFieldName(name); } /* /********************************************************** /* Output method implementations, structural /********************************************************** */ @Override public final void writeStartArray() throws IOException, JsonGenerationException { _verifyValueWrite("start an array"); _writeContext = _writeContext.createChildArrayContext(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeStartArray(this); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_LBRACKET; } } @Override public final void writeEndArray() throws IOException, JsonGenerationException { if (!_writeContext.inArray()) { _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc()); } if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount()); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_RBRACKET; } _writeContext = _writeContext.getParent(); } @Override public final void writeStartObject() throws IOException, JsonGenerationException { _verifyValueWrite("start an object"); _writeContext = _writeContext.createChildObjectContext(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeStartObject(this); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_LCURLY; } } @Override public final void writeEndObject() throws IOException, JsonGenerationException { if (!_writeContext.inObject()) { _reportError("Current context not an object but "+_writeContext.getTypeDesc()); } _writeContext = _writeContext.getParent(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount()); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_RCURLY; } } protected final void _writeFieldName(String name) throws IOException, JsonGenerationException { /* To support [JACKSON-46], we'll do this: * (Question: should quoting of spaces (etc) still be enabled?) */ if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) { _writeStringSegments(name); return; } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; // The beef: final int len = name.length(); if (len <= _charBufferLength) { // yes, fits right in name.getChars(0, len, _charBuffer, 0); // But as one segment, or multiple? if (len <= _outputMaxContiguous) { if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space _flushBuffer(); } _writeStringSegment(_charBuffer, 0, len); } else { _writeStringSegments(_charBuffer, 0, len); } } else { _writeStringSegments(name); } // and closing quotes; need room for one more char: if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } protected final void _writeFieldName(SerializableString name) throws IOException, JsonGenerationException { byte[] raw = name.asQuotedUTF8(); if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) { _writeBytes(raw); return; } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; // Can do it all in buffer? final int len = raw.length; if ((_outputTail + len + 1) < _outputEnd) { // yup System.arraycopy(raw, 0, _outputBuffer, _outputTail, len); _outputTail += len; _outputBuffer[_outputTail++] = BYTE_QUOTE; } else { _writeBytes(raw); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } } /** * Specialized version of _writeFieldName, off-lined * to keep the "fast path" as simple (and hopefully fast) as possible. */ protected final void _writePPFieldName(String name, boolean commaBefore) throws IOException, JsonGenerationException { if (commaBefore) { _cfgPrettyPrinter.writeObjectEntrySeparator(this); } else { _cfgPrettyPrinter.beforeObjectEntries(this); } if (isEnabled(Feature.QUOTE_FIELD_NAMES)) { // standard if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; final int len = name.length(); if (len <= _charBufferLength) { // yes, fits right in name.getChars(0, len, _charBuffer, 0); // But as one segment, or multiple? if (len <= _outputMaxContiguous) { if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space _flushBuffer(); } _writeStringSegment(_charBuffer, 0, len); } else { _writeStringSegments(_charBuffer, 0, len); } } else { _writeStringSegments(name); } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } else { // non-standard, omit quotes _writeStringSegments(name); } } protected final void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException, JsonGenerationException { if (commaBefore) { _cfgPrettyPrinter.writeObjectEntrySeparator(this); } else { _cfgPrettyPrinter.beforeObjectEntries(this); } boolean addQuotes = isEnabled(Feature.QUOTE_FIELD_NAMES); // standard if (addQuotes) { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } _writeBytes(name.asQuotedUTF8()); if (addQuotes) { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } } /* /********************************************************** /* Output method implementations, textual /********************************************************** */ @Override public void writeString(String text) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (text == null) { _writeNull(); return; } // First: can we make a local copy of chars that make up text? final int len = text.length(); if (len > _charBufferLength) { // nope: off-line handling _writeLongString(text); return; } // yes: good. text.getChars(0, len, _charBuffer, 0); // Output: if we can't guarantee it fits in output buffer, off-line as well: if (len > _outputMaxContiguous) { _writeLongString(_charBuffer, 0, len); return; } if ((_outputTail + len + 2) > _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _writeStringSegment(_charBuffer, 0, len); // we checked space already above _outputBuffer[_outputTail++] = BYTE_QUOTE; } private final void _writeLongString(String text) throws IOException, JsonGenerationException { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _writeStringSegments(text); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } private final void _writeLongString(char[] text, int offset, int len) throws IOException, JsonGenerationException { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _writeStringSegments(_charBuffer, 0, len); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } @Override public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; // One or multiple segments? if (len <= _outputMaxContiguous) { if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space _flushBuffer(); } _writeStringSegment(text, offset, len); } else { _writeStringSegments(text, offset, len); } // And finally, closing quotes if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } @Override public final void writeString(SerializableString text) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _writeBytes(text.asQuotedUTF8()); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } @Override public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _writeBytes(text, offset, length); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } @Override public void writeUTF8String(byte[] text, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; // One or multiple segments? if (len <= _outputMaxContiguous) { _writeUTF8Segment(text, offset, len); } else { _writeUTF8Segments(text, offset, len); } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } /* /********************************************************** /* Output method implementations, unprocessed ("raw") /********************************************************** */ @Override public void writeRaw(String text) throws IOException, JsonGenerationException { int start = 0; int len = text.length(); while (len > 0) { char[] buf = _charBuffer; final int blen = buf.length; final int len2 = (len < blen) ? len : blen; text.getChars(start, start+len2, buf, 0); writeRaw(buf, 0, len2); start += len2; len -= len2; } } @Override public void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException { while (len > 0) { char[] buf = _charBuffer; final int blen = buf.length; final int len2 = (len < blen) ? len : blen; text.getChars(offset, offset+len2, buf, 0); writeRaw(buf, 0, len2); offset += len2; len -= len2; } } // @TODO: rewrite for speed... @Override public final void writeRaw(char[] cbuf, int offset, int len) throws IOException, JsonGenerationException { // First: if we have 3 x charCount spaces, we know it'll fit just fine { int len3 = len+len+len; if ((_outputTail + len3) > _outputEnd) { // maybe we could flush? if (_outputEnd < len3) { // wouldn't be enough... _writeSegmentedRaw(cbuf, offset, len); return; } // yes, flushing brings enough space _flushBuffer(); } } len += offset; // now marks the end // Note: here we know there is enough room, hence no output boundary checks main_loop: while (offset < len) { inner_loop: while (true) { int ch = (int) cbuf[offset]; if (ch > 0x7F) { break inner_loop; } _outputBuffer[_outputTail++] = (byte) ch; if (++offset >= len) { break main_loop; } } char ch = cbuf[offset++]; if (ch < 0x800) { // 2-byte? _outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6)); _outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f)); } else { _outputRawMultiByteChar(ch, cbuf, offset, len); } } } @Override public void writeRaw(char ch) throws IOException, JsonGenerationException { if ((_outputTail + 3) >= _outputEnd) { _flushBuffer(); } final byte[] bbuf = _outputBuffer; if (ch <= 0x7F) { bbuf[_outputTail++] = (byte) ch; } else if (ch < 0x800) { // 2-byte? bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6)); bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f)); } else { _outputRawMultiByteChar(ch, null, 0, 0); } } /** * Helper method called when it is possible that output of raw section * to output may cross buffer boundary */ private final void _writeSegmentedRaw(char[] cbuf, int offset, int len) throws IOException, JsonGenerationException { final int end = _outputEnd; final byte[] bbuf = _outputBuffer; main_loop: while (offset < len) { inner_loop: while (true) { int ch = (int) cbuf[offset]; if (ch >= 0x80) { break inner_loop; } // !!! TODO: fast(er) writes (roll input, output checks in one) if (_outputTail >= end) { _flushBuffer(); } bbuf[_outputTail++] = (byte) ch; if (++offset >= len) { break main_loop; } } if ((_outputTail + 3) >= _outputEnd) { _flushBuffer(); } char ch = cbuf[offset++]; if (ch < 0x800) { // 2-byte? bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6)); bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f)); } else { _outputRawMultiByteChar(ch, cbuf, offset, len); } } } /* /********************************************************** /* Output method implementations, base64-encoded binary /********************************************************** */ @Override public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write binary value"); // Starting quotes if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _writeBinary(b64variant, data, offset, offset+len); // and closing quotes if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } /* /********************************************************** /* Output method implementations, primitive /********************************************************** */ @Override public void writeNumber(int i) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); // up to 10 digits and possible minus sign if ((_outputTail + 11) >= _outputEnd) { _flushBuffer(); } if (_cfgNumbersAsStrings) { _writeQuotedInt(i); return; } _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); } private final void _writeQuotedInt(int i) throws IOException { if ((_outputTail + 13) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); _outputBuffer[_outputTail++] = BYTE_QUOTE; } @Override public void writeNumber(long l) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); if (_cfgNumbersAsStrings) { _writeQuotedLong(l); return; } if ((_outputTail + 21) >= _outputEnd) { // up to 20 digits, minus sign _flushBuffer(); } _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); } private final void _writeQuotedLong(long l) throws IOException { if ((_outputTail + 23) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); _outputBuffer[_outputTail++] = BYTE_QUOTE; } @Override public void writeNumber(BigInteger value) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); if (value == null) { _writeNull(); } else if (_cfgNumbersAsStrings) { _writeQuotedRaw(value); } else { writeRaw(value.toString()); } } @Override public void writeNumber(double d) throws IOException, JsonGenerationException { if (_cfgNumbersAsStrings || // [JACKSON-139] (((Double.isNaN(d) || Double.isInfinite(d)) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) { writeString(String.valueOf(d)); return; } // What is the max length for doubles? 40 chars? _verifyValueWrite("write number"); writeRaw(String.valueOf(d)); } @Override public void writeNumber(float f) throws IOException, JsonGenerationException { if (_cfgNumbersAsStrings || // [JACKSON-139] (((Float.isNaN(f) || Float.isInfinite(f)) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) { writeString(String.valueOf(f)); return; } // What is the max length for floats? _verifyValueWrite("write number"); writeRaw(String.valueOf(f)); } @Override public void writeNumber(BigDecimal value) throws IOException, JsonGenerationException { // Don't really know max length for big decimal, no point checking _verifyValueWrite("write number"); if (value == null) { _writeNull(); } else if (_cfgNumbersAsStrings) { _writeQuotedRaw(value); } else { writeRaw(value.toString()); } } @Override public void writeNumber(String encodedValue) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); if (_cfgNumbersAsStrings) { _writeQuotedRaw(encodedValue); } else { writeRaw(encodedValue); } } private final void _writeQuotedRaw(Object value) throws IOException { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; writeRaw(value.toString()); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = BYTE_QUOTE; } @Override public void writeBoolean(boolean state) throws IOException, JsonGenerationException { _verifyValueWrite("write boolean value"); if ((_outputTail + 5) >= _outputEnd) { _flushBuffer(); } byte[] keyword = state ? TRUE_BYTES : FALSE_BYTES; int len = keyword.length; System.arraycopy(keyword, 0, _outputBuffer, _outputTail, len); _outputTail += len; } @Override public void writeNull() throws IOException, JsonGenerationException { _verifyValueWrite("write null value"); _writeNull(); } /* /********************************************************** /* Implementations for other methods /********************************************************** */ @Override protected final void _verifyValueWrite(String typeMsg) throws IOException, JsonGenerationException { int status = _writeContext.writeValue(); if (status == JsonWriteContext.STATUS_EXPECT_NAME) { _reportError("Can not "+typeMsg+", expecting field name"); } if (_cfgPrettyPrinter == null) { byte b; switch (status) { case JsonWriteContext.STATUS_OK_AFTER_COMMA: b = BYTE_COMMA; break; case JsonWriteContext.STATUS_OK_AFTER_COLON: b = BYTE_COLON; break; case JsonWriteContext.STATUS_OK_AFTER_SPACE: b = BYTE_SPACE; break; case JsonWriteContext.STATUS_OK_AS_IS: default: return; } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail] = b; ++_outputTail; return; } // Otherwise, pretty printer knows what to do... _verifyPrettyValueWrite(typeMsg, status); } protected final void _verifyPrettyValueWrite(String typeMsg, int status) throws IOException, JsonGenerationException { // If we have a pretty printer, it knows what to do: switch (status) { case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array _cfgPrettyPrinter.writeArrayValueSeparator(this); break; case JsonWriteContext.STATUS_OK_AFTER_COLON: _cfgPrettyPrinter.writeObjectFieldValueSeparator(this); break; case JsonWriteContext.STATUS_OK_AFTER_SPACE: _cfgPrettyPrinter.writeRootValueSeparator(this); break; case JsonWriteContext.STATUS_OK_AS_IS: // First entry, but of which context? if (_writeContext.inArray()) { _cfgPrettyPrinter.beforeArrayValues(this); } else if (_writeContext.inObject()) { _cfgPrettyPrinter.beforeObjectEntries(this); } break; default: _cantHappen(); break; } } /* /********************************************************** /* Low-level output handling /********************************************************** */ @Override public final void flush() throws IOException { _flushBuffer(); if (_outputStream != null) { if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) { _outputStream.flush(); } } } @Override public void close() throws IOException { super.close(); /* 05-Dec-2008, tatu: To add [JACKSON-27], need to close open * scopes. */ // First: let's see that we still have buffers... if (_outputBuffer != null && isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) { while (true) { JsonStreamContext ctxt = getOutputContext(); if (ctxt.inArray()) { writeEndArray(); } else if (ctxt.inObject()) { writeEndObject(); } else { break; } } } _flushBuffer(); /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying Reader, unless we "own" it, or auto-closing * feature is enabled. * One downside: when using UTF8Writer, underlying buffer(s) * may not be properly recycled if we don't close the writer. */ if (_outputStream != null) { if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) { _outputStream.close(); } else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) { // If we can't close it, we should at least flush _outputStream.flush(); } } // Internal buffer(s) generator has can now be released as well _releaseBuffers(); } @Override protected void _releaseBuffers() { byte[] buf = _outputBuffer; if (buf != null && _bufferRecyclable) { _outputBuffer = null; _ioContext.releaseWriteEncodingBuffer(buf); } char[] cbuf = _charBuffer; if (cbuf != null) { _charBuffer = null; _ioContext.releaseConcatBuffer(cbuf); } } /* /********************************************************** /* Internal methods, low-level writing, raw bytes /********************************************************** */ private final void _writeBytes(byte[] bytes) throws IOException { final int len = bytes.length; if ((_outputTail + len) > _outputEnd) { _flushBuffer(); // still not enough? if (len > MAX_BYTES_TO_BUFFER) { _outputStream.write(bytes, 0, len); return; } } System.arraycopy(bytes, 0, _outputBuffer, _outputTail, len); _outputTail += len; } private final void _writeBytes(byte[] bytes, int offset, int len) throws IOException { if ((_outputTail + len) > _outputEnd) { _flushBuffer(); // still not enough? if (len > MAX_BYTES_TO_BUFFER) { _outputStream.write(bytes, offset, len); return; } } System.arraycopy(bytes, offset, _outputBuffer, _outputTail, len); _outputTail += len; } /* /********************************************************** /* Internal methods, mid-level writing, String segments /********************************************************** */ /** * Method called when String to write is long enough not to fit * completely in temporary copy buffer. If so, we will actually * copy it in small enough chunks so it can be directly fed * to single-segment writes (instead of maximum slices that * would fit in copy buffer) */ private final void _writeStringSegments(String text) throws IOException, JsonGenerationException { int left = text.length(); int offset = 0; final char[] cbuf = _charBuffer; while (left > 0) { int len = Math.min(_outputMaxContiguous, left); text.getChars(offset, offset+len, cbuf, 0); if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space _flushBuffer(); } _writeStringSegment(cbuf, 0, len); offset += len; left -= len; } } /** * Method called when character sequence to write is long enough that * its maximum encoded and escaped form is not guaranteed to fit in * the output buffer. If so, we will need to choose smaller output * chunks to write at a time. */ private final void _writeStringSegments(char[] cbuf, int offset, int totalLen) throws IOException, JsonGenerationException { do { int len = Math.min(_outputMaxContiguous, totalLen); if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space _flushBuffer(); } _writeStringSegment(cbuf, offset, len); offset += len; totalLen -= len; } while (totalLen > 0); } /* /********************************************************** /* Internal methods, low-level writing, text segments /********************************************************** */ /** * This method called when the string content is already in * a char buffer, and its maximum total encoded and escaped length * can not exceed size of the output buffer. * Caller must ensure that there is enough space in output buffer, * assuming case of all non-escaped ASCII characters, as well as * potentially enough space for other cases (but not necessarily flushed) */ private final void _writeStringSegment(char[] cbuf, int offset, int len) throws IOException, JsonGenerationException { // note: caller MUST ensure (via flushing) there's room for ASCII only // Fast+tight loop for ASCII-only, no-escaping-needed output len += offset; // becomes end marker, then int outputPtr = _outputTail; final byte[] outputBuffer = _outputBuffer; final int[] escCodes = _outputEscapes; while (offset < len) { int ch = cbuf[offset]; // note: here we know that (ch > 0x7F) will cover case of escaping non-ASCII too: if (ch > 0x7F || escCodes[ch] != 0) { break; } outputBuffer[outputPtr++] = (byte) ch; ++offset; } _outputTail = outputPtr; if (offset < len) { // [JACKSON-106] if (_characterEscapes != null) { _writeCustomStringSegment2(cbuf, offset, len); // [JACKSON-102] } else if (_maximumNonEscapedChar == 0) { _writeStringSegment2(cbuf, offset, len); } else { _writeStringSegmentASCII2(cbuf, offset, len); } } } /** * Secondary method called when content contains characters to escape, * and/or multi-byte UTF-8 characters. */ private final void _writeStringSegment2(final char[] cbuf, int offset, final int end) throws IOException, JsonGenerationException { // Ok: caller guarantees buffer can have room; but that may require flushing: if ((_outputTail + 6 * (end - offset)) > _outputEnd) { _flushBuffer(); } int outputPtr = _outputTail; final byte[] outputBuffer = _outputBuffer; final int[] escCodes = _outputEscapes; while (offset < end) { int ch = cbuf[offset++]; if (ch <= 0x7F) { if (escCodes[ch] == 0) { outputBuffer[outputPtr++] = (byte) ch; continue; } int escape = escCodes[ch]; if (escape > 0) { // 2-char escape, fine outputBuffer[outputPtr++] = BYTE_BACKSLASH; outputBuffer[outputPtr++] = (byte) escape; } else { // ctrl-char, 6-byte escape... outputPtr = _writeGenericEscape(ch, outputPtr); } continue; } if (ch <= 0x7FF) { // fine, just needs 2 byte output outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6)); outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f)); } else { outputPtr = _outputMultiByteChar(ch, outputPtr); } } _outputTail = outputPtr; } /* /********************************************************** /* Internal methods, low-level writing, text segment /* with additional escaping (ASCII or such) /* (since 1.8; see [JACKSON-102]) /********************************************************** */ /** * Same as _writeStringSegment2(char[], ...) _outputEnd) { _flushBuffer(); } int outputPtr = _outputTail; final byte[] outputBuffer = _outputBuffer; final int[] escCodes = _outputEscapes; final int maxUnescaped = _maximumNonEscapedChar; while (offset < end) { int ch = cbuf[offset++]; if (ch <= 0x7F) { if (escCodes[ch] == 0) { outputBuffer[outputPtr++] = (byte) ch; continue; } int escape = escCodes[ch]; if (escape > 0) { // 2-char escape, fine outputBuffer[outputPtr++] = BYTE_BACKSLASH; outputBuffer[outputPtr++] = (byte) escape; } else { // ctrl-char, 6-byte escape... outputPtr = _writeGenericEscape(ch, outputPtr); } continue; } if (ch > maxUnescaped) { // [JACKSON-102] Allow forced escaping if non-ASCII (etc) chars: outputPtr = _writeGenericEscape(ch, outputPtr); continue; } if (ch <= 0x7FF) { // fine, just needs 2 byte output outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6)); outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f)); } else { outputPtr = _outputMultiByteChar(ch, outputPtr); } } _outputTail = outputPtr; } /* /********************************************************** /* Internal methods, low-level writing, text segment /* with fully custom escaping (and possibly escaping of non-ASCII /********************************************************** */ /** * Same as _writeStringSegmentASCII2(char[], ...) _outputEnd) { _flushBuffer(); } int outputPtr = _outputTail; final byte[] outputBuffer = _outputBuffer; final int[] escCodes = _outputEscapes; // may or may not have this limit final int maxUnescaped = (_maximumNonEscapedChar <= 0) ? 0xFFFF : _maximumNonEscapedChar; final CharacterEscapes customEscapes = _characterEscapes; // non-null while (offset < end) { int ch = cbuf[offset++]; if (ch <= 0x7F) { if (escCodes[ch] == 0) { outputBuffer[outputPtr++] = (byte) ch; continue; } int escape = escCodes[ch]; if (escape > 0) { // 2-char escape, fine outputBuffer[outputPtr++] = BYTE_BACKSLASH; outputBuffer[outputPtr++] = (byte) escape; } else if (escape == CharacterEscapes.ESCAPE_CUSTOM) { SerializableString esc = customEscapes.getEscapeSequence(ch); if (esc == null) { throw new JsonGenerationException("Invalid custom escape definitions; custom escape not found for character code 0x" +Integer.toHexString(ch)+", although was supposed to have one"); } outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset); } else { // ctrl-char, 6-byte escape... outputPtr = _writeGenericEscape(ch, outputPtr); } continue; } if (ch > maxUnescaped) { // [JACKSON-102] Allow forced escaping if non-ASCII (etc) chars: outputPtr = _writeGenericEscape(ch, outputPtr); continue; } SerializableString esc = customEscapes.getEscapeSequence(ch); if (esc != null) { outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset); continue; } if (ch <= 0x7FF) { // fine, just needs 2 byte output outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6)); outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f)); } else { outputPtr = _outputMultiByteChar(ch, outputPtr); } } _outputTail = outputPtr; } private int _writeCustomEscape(byte[] outputBuffer, int outputPtr, SerializableString esc, int remainingChars) throws IOException, JsonGenerationException { byte[] raw = esc.asUnquotedUTF8(); // must be escaped at this point, shouldn't double-quote int len = raw.length; if (len > 6) { // may violate constraints we have, do offline return _handleLongCustomEscape(outputBuffer, outputPtr, _outputEnd, raw, remainingChars); } // otherwise will fit without issues, so: System.arraycopy(raw, 0, outputBuffer, outputPtr, len); return (outputPtr + len); } private int _handleLongCustomEscape(byte[] outputBuffer, int outputPtr, int outputEnd, byte[] raw, int remainingChars) throws IOException, JsonGenerationException { int len = raw.length; if ((outputPtr + len) > outputEnd) { _outputTail = outputPtr; _flushBuffer(); outputPtr = _outputTail; if (len > outputBuffer.length) { // very unlikely, but possible... _outputStream.write(raw, 0, len); return outputPtr; } System.arraycopy(raw, 0, outputBuffer, outputPtr, len); outputPtr += len; } // but is the invariant still obeyed? If not, flush once more if ((outputPtr + 6 * remainingChars) > outputEnd) { _flushBuffer(); return _outputTail; } return outputPtr; } /* /********************************************************** /* Internal methods, low-level writing, "raw UTF-8" segments /********************************************************** */ /** * Method called when UTF-8 encoded (but NOT yet escaped!) content is not guaranteed * to fit in the output buffer after escaping; as such, we just need to * chunk writes. */ private final void _writeUTF8Segments(byte[] utf8, int offset, int totalLen) throws IOException, JsonGenerationException { do { int len = Math.min(_outputMaxContiguous, totalLen); _writeUTF8Segment(utf8, offset, len); offset += len; totalLen -= len; } while (totalLen > 0); } private final void _writeUTF8Segment(byte[] utf8, final int offset, final int len) throws IOException, JsonGenerationException { // fast loop to see if escaping is needed; don't copy, just look final int[] escCodes = _outputEscapes; for (int ptr = offset, end = offset + len; ptr < end; ) { // 28-Feb-2011, tatu: escape codes just cover 7-bit range, so: int ch = utf8[ptr++]; if ((ch >= 0) && escCodes[ch] != 0) { _writeUTF8Segment2(utf8, offset, len); return; } } // yes, fine, just copy the sucker if ((_outputTail + len) > _outputEnd) { // enough room or need to flush? _flushBuffer(); // but yes once we flush (caller guarantees length restriction) } System.arraycopy(utf8, offset, _outputBuffer, _outputTail, len); _outputTail += len; } private final void _writeUTF8Segment2(final byte[] utf8, int offset, int len) throws IOException, JsonGenerationException { int outputPtr = _outputTail; // Ok: caller guarantees buffer can have room; but that may require flushing: if ((outputPtr + (len * 6)) > _outputEnd) { _flushBuffer(); outputPtr = _outputTail; } final byte[] outputBuffer = _outputBuffer; final int[] escCodes = _outputEscapes; len += offset; // so 'len' becomes 'end' while (offset < len) { byte b = utf8[offset++]; int ch = b; if (ch < 0 || escCodes[ch] == 0) { outputBuffer[outputPtr++] = b; continue; } int escape = escCodes[ch]; if (escape > 0) { // 2-char escape, fine outputBuffer[outputPtr++] = BYTE_BACKSLASH; outputBuffer[outputPtr++] = (byte) escape; } else { // ctrl-char, 6-byte escape... outputPtr = _writeGenericEscape(ch, outputPtr); } } _outputTail = outputPtr; } /* /********************************************************** /* Internal methods, low-level writing, base64 encoded /********************************************************** */ protected void _writeBinary(Base64Variant b64variant, byte[] input, int inputPtr, final int inputEnd) throws IOException, JsonGenerationException { // Encoding is by chunks of 3 input, 4 output chars, so: int safeInputEnd = inputEnd - 3; // Let's also reserve room for possible (and quoted) lf char each round int safeOutputEnd = _outputEnd - 6; int chunksBeforeLF = b64variant.getMaxLineLength() >> 2; // Ok, first we loop through all full triplets of data: while (inputPtr <= safeInputEnd) { if (_outputTail > safeOutputEnd) { // need to flush _flushBuffer(); } // First, mash 3 bytes into lsb of 32-bit int int b24 = ((int) input[inputPtr++]) << 8; b24 |= ((int) input[inputPtr++]) & 0xFF; b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF); _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail); if (--chunksBeforeLF <= 0) { // note: must quote in JSON value _outputBuffer[_outputTail++] = '\\'; _outputBuffer[_outputTail++] = 'n'; chunksBeforeLF = b64variant.getMaxLineLength() >> 2; } } // And then we may have 1 or 2 leftover bytes to encode int inputLeft = inputEnd - inputPtr; // 0, 1 or 2 if (inputLeft > 0) { // yes, but do we have room for output? if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but... _flushBuffer(); } int b24 = ((int) input[inputPtr++]) << 16; if (inputLeft == 2) { b24 |= (((int) input[inputPtr++]) & 0xFF) << 8; } _outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail); } } /* /********************************************************** /* Internal methods, character escapes/encoding /********************************************************** */ /** * Method called to output a character that is beyond range of * 1- and 2-byte UTF-8 encodings, when outputting "raw" * text (meaning it is not to be escaped or quoted) */ private final int _outputRawMultiByteChar(int ch, char[] cbuf, int inputOffset, int inputLen) throws IOException { // Let's handle surrogates gracefully (as 4 byte output): if (ch >= SURR1_FIRST) { if (ch <= SURR2_LAST) { // yes, outside of BMP // Do we have second part? if (inputOffset >= inputLen) { // nope... have to note down _reportError("Split surrogate on writeRaw() input (last character)"); } _outputSurrogates(ch, cbuf[inputOffset]); return (inputOffset+1); } } final byte[] bbuf = _outputBuffer; bbuf[_outputTail++] = (byte) (0xe0 | (ch >> 12)); bbuf[_outputTail++] = (byte) (0x80 | ((ch >> 6) & 0x3f)); bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f)); return inputOffset; } protected final void _outputSurrogates(int surr1, int surr2) throws IOException { int c = _decodeSurrogate(surr1, surr2); if ((_outputTail + 4) > _outputEnd) { _flushBuffer(); } final byte[] bbuf = _outputBuffer; bbuf[_outputTail++] = (byte) (0xf0 | (c >> 18)); bbuf[_outputTail++] = (byte) (0x80 | ((c >> 12) & 0x3f)); bbuf[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f)); bbuf[_outputTail++] = (byte) (0x80 | (c & 0x3f)); } /** * * @param ch * @param outputPtr Position within output buffer to append multi-byte in * * @return New output position after appending * * @throws IOException */ private final int _outputMultiByteChar(int ch, int outputPtr) throws IOException { byte[] bbuf = _outputBuffer; if (ch >= SURR1_FIRST && ch <= SURR2_LAST) { // yes, outside of BMP; add an escape bbuf[outputPtr++] = BYTE_BACKSLASH; bbuf[outputPtr++] = BYTE_u; bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF]; bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF]; bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF]; bbuf[outputPtr++] = HEX_CHARS[ch & 0xF]; } else { bbuf[outputPtr++] = (byte) (0xe0 | (ch >> 12)); bbuf[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f)); bbuf[outputPtr++] = (byte) (0x80 | (ch & 0x3f)); } return outputPtr; } protected final int _decodeSurrogate(int surr1, int surr2) throws IOException { // First is known to be valid, but how about the other? if (surr2 < SURR2_FIRST || surr2 > SURR2_LAST) { String msg = "Incomplete surrogate pair: first char 0x"+Integer.toHexString(surr1)+", second 0x"+Integer.toHexString(surr2); _reportError(msg); } int c = 0x10000 + ((surr1 - SURR1_FIRST) << 10) + (surr2 - SURR2_FIRST); return c; } private final void _writeNull() throws IOException { if ((_outputTail + 4) >= _outputEnd) { _flushBuffer(); } System.arraycopy(NULL_BYTES, 0, _outputBuffer, _outputTail, 4); _outputTail += 4; } /** * Method called to write a generic Unicode escape for given character. * * @param charToEscape Character to escape using escape sequence (\\uXXXX) */ private int _writeGenericEscape(int charToEscape, int outputPtr) throws IOException { final byte[] bbuf = _outputBuffer; bbuf[outputPtr++] = BYTE_BACKSLASH; bbuf[outputPtr++] = BYTE_u; if (charToEscape > 0xFF) { int hi = (charToEscape >> 8) & 0xFF; bbuf[outputPtr++] = HEX_CHARS[hi >> 4]; bbuf[outputPtr++] = HEX_CHARS[hi & 0xF]; charToEscape &= 0xFF; } else { bbuf[outputPtr++] = BYTE_0; bbuf[outputPtr++] = BYTE_0; } // We know it's a control char, so only the last 2 chars are non-0 bbuf[outputPtr++] = HEX_CHARS[charToEscape >> 4]; bbuf[outputPtr++] = HEX_CHARS[charToEscape & 0xF]; return outputPtr; } protected final void _flushBuffer() throws IOException { int len = _outputTail; if (len > 0) { _outputTail = 0; _outputStream.write(_outputBuffer, 0, len); } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/StreamBasedParserBase.java0000644000175000017500000001363411655120726030116 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import org.codehaus.jackson.io.IOContext; /** * This is a simple low-level input reader base class, used by * JSON parser. It is used when underlying input source is * a byte stream such as {@link InputStream}. * The reason for sub-classing (over composition) * is due to need for direct access to low-level byte buffers * and positions. * * @author Tatu Saloranta * * @deprecated Since 1.9, sub-classes should just embed code from here */ @Deprecated public abstract class StreamBasedParserBase extends JsonParserBase { /* /********************************************************** /* Configuration /********************************************************** */ /** * Input stream that can be used for reading more content, if one * in use. May be null, if input comes just as a full buffer, * or if the stream has been closed. */ protected InputStream _inputStream; /* /********************************************************** /* Current input data /********************************************************** */ /** * Current buffer from which data is read; generally data is read into * buffer from input source, but in some cases pre-loaded buffer * is handed to the parser. */ protected byte[] _inputBuffer; /** * Flag that indicates whether the input buffer is recycable (and * needs to be returned to recycler once we are done) or not. *

* If it is not, it also means that parser can NOT modify underlying * buffer. */ protected boolean _bufferRecyclable; /* /********************************************************** /* Life-cycle /********************************************************** */ protected StreamBasedParserBase(IOContext ctxt, int features, InputStream in, byte[] inputBuffer, int start, int end, boolean bufferRecyclable) { super(ctxt, features); _inputStream = in; _inputBuffer = inputBuffer; _inputPtr = start; _inputEnd = end; _bufferRecyclable = bufferRecyclable; } /* /********************************************************** /* Overrides /********************************************************** */ @Override public int releaseBuffered(OutputStream out) throws IOException { int count = _inputEnd - _inputPtr; if (count < 1) { return 0; } // let's just advance ptr to end int origPtr = _inputPtr; out.write(_inputBuffer, origPtr, count); return count; } @Override public Object getInputSource() { return _inputStream; } /* /********************************************************** /* Low-level reading, other /********************************************************** */ @Override protected final boolean loadMore() throws IOException { _currInputProcessed += _inputEnd; _currInputRowStart -= _inputEnd; if (_inputStream != null) { int count = _inputStream.read(_inputBuffer, 0, _inputBuffer.length); if (count > 0) { _inputPtr = 0; _inputEnd = count; return true; } // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes"); } } return false; } /** * Helper method that will try to load at least specified number bytes in * input buffer, possible moving existing data around if necessary * * @since 1.6 */ protected final boolean _loadToHaveAtLeast(int minAvailable) throws IOException { // No input stream, no leading (either we are closed, or have non-stream input source) if (_inputStream == null) { return false; } // Need to move remaining data in front? int amount = _inputEnd - _inputPtr; if (amount > 0 && _inputPtr > 0) { _currInputProcessed += _inputPtr; _currInputRowStart -= _inputPtr; System.arraycopy(_inputBuffer, _inputPtr, _inputBuffer, 0, amount); _inputEnd = amount; } else { _inputEnd = 0; } _inputPtr = 0; while (_inputEnd < minAvailable) { int count = _inputStream.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd); if (count < 1) { // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("InputStream.read() returned 0 characters when trying to read "+amount+" bytes"); } return false; } _inputEnd += count; } return true; } @Override protected void _closeInput() throws IOException { /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying InputStream, unless we "own" it, or auto-closing * feature is enabled. */ if (_inputStream != null) { if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) { _inputStream.close(); } _inputStream = null; } } @Override protected void _releaseBuffers() throws IOException { super._releaseBuffers(); if (_bufferRecyclable) { byte[] buf = _inputBuffer; if (buf != null) { _inputBuffer = null; _ioContext.releaseReadIOBuffer(buf); } } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/JsonParserBase.java0000644000175000017500000011004411655120726026626 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.io.IOContext; import org.codehaus.jackson.io.NumberInput; import org.codehaus.jackson.util.ByteArrayBuilder; import org.codehaus.jackson.util.TextBuffer; import org.codehaus.jackson.util.VersionUtil; /** * Intermediate base class used by all Jackson {@link JsonParser} * implementations. Contains most common things that are independent * of actual underlying input source * * @author Tatu Saloranta */ public abstract class JsonParserBase extends JsonParserMinimalBase { /* /********************************************************** /* Generic I/O state /********************************************************** */ /** * I/O context for this reader. It handles buffer allocation * for the reader. */ final protected IOContext _ioContext; /** * Flag that indicates whether parser is closed or not. Gets * set when parser is either closed by explicit call * ({@link #close}) or when end-of-input is reached. */ protected boolean _closed; /* /********************************************************** /* Current input data /********************************************************** */ // Note: type of actual buffer depends on sub-class, can't include /** * Pointer to next available character in buffer */ protected int _inputPtr = 0; /** * Index of character after last available one in the buffer. */ protected int _inputEnd = 0; /* /********************************************************** /* Current input location information /********************************************************** */ /** * Number of characters/bytes that were contained in previous blocks * (blocks that were already processed prior to the current buffer). */ protected long _currInputProcessed = 0L; /** * Current row location of current point in input buffer, starting * from 1, if available. */ protected int _currInputRow = 1; /** * Current index of the first character of the current row in input * buffer. Needed to calculate column position, if necessary; benefit * of not having column itself is that this only has to be updated * once per line. */ protected int _currInputRowStart = 0; /* /********************************************************** /* Information about starting location of event /* Reader is pointing to; updated on-demand /********************************************************** */ // // // Location info at point when current token was started /** * Total number of bytes/characters read before start of current token. * For big (gigabyte-sized) sizes are possible, needs to be long, * unlike pointers and sizes related to in-memory buffers. */ protected long _tokenInputTotal = 0; /** * Input row on which current token starts, 1-based */ protected int _tokenInputRow = 1; /** * Column on input row that current token starts; 0-based (although * in the end it'll be converted to 1-based) */ protected int _tokenInputCol = 0; /* /********************************************************** /* Parsing state /********************************************************** */ /** * Information about parser context, context in which * the next token is to be parsed (root, array, object). */ protected JsonReadContext _parsingContext; /** * Secondary token related to the next token after current one; * used if its type is known. This may be value token that * follows FIELD_NAME, for example. */ protected JsonToken _nextToken; /* /********************************************************** /* Buffer(s) for local name(s) and text content /********************************************************** */ /** * Buffer that contains contents of String values, including * field names if necessary (name split across boundary, * contains escape sequence, or access needed to char array) */ protected final TextBuffer _textBuffer; /** * Temporary buffer that is needed if field name is accessed * using {@link #getTextCharacters} method (instead of String * returning alternatives) */ protected char[] _nameCopyBuffer = null; /** * Flag set to indicate whether the field name is available * from the name copy buffer or not (in addition to its String * representation being available via read context) */ protected boolean _nameCopied = false; /** * ByteArrayBuilder is needed if 'getBinaryValue' is called. If so, * we better reuse it for remainder of content. */ protected ByteArrayBuilder _byteArrayBuilder = null; /** * We will hold on to decoded binary data, for duration of * current event, so that multiple calls to * {@link #getBinaryValue} will not need to decode data more * than once. */ protected byte[] _binaryValue; /* /********************************************************** /* Constants and fields of former 'JsonNumericParserBase' /********************************************************** */ final protected static int NR_UNKNOWN = 0; // First, integer types final protected static int NR_INT = 0x0001; final protected static int NR_LONG = 0x0002; final protected static int NR_BIGINT = 0x0004; // And then floating point types final protected static int NR_DOUBLE = 0x008; final protected static int NR_BIGDECIMAL = 0x0010; // Also, we need some numeric constants final static BigDecimal BD_MIN_LONG = new BigDecimal(Long.MIN_VALUE); final static BigDecimal BD_MAX_LONG = new BigDecimal(Long.MAX_VALUE); final static BigDecimal BD_MIN_INT = new BigDecimal(Long.MIN_VALUE); final static BigDecimal BD_MAX_INT = new BigDecimal(Long.MAX_VALUE); final static long MIN_INT_L = (long) Integer.MIN_VALUE; final static long MAX_INT_L = (long) Integer.MAX_VALUE; // These are not very accurate, but have to do... (for bounds checks) final static double MIN_LONG_D = (double) Long.MIN_VALUE; final static double MAX_LONG_D = (double) Long.MAX_VALUE; final static double MIN_INT_D = (double) Integer.MIN_VALUE; final static double MAX_INT_D = (double) Integer.MAX_VALUE; // Digits, numeric final protected static int INT_0 = '0'; final protected static int INT_1 = '1'; final protected static int INT_2 = '2'; final protected static int INT_3 = '3'; final protected static int INT_4 = '4'; final protected static int INT_5 = '5'; final protected static int INT_6 = '6'; final protected static int INT_7 = '7'; final protected static int INT_8 = '8'; final protected static int INT_9 = '9'; final protected static int INT_MINUS = '-'; final protected static int INT_PLUS = '+'; final protected static int INT_DECIMAL_POINT = '.'; final protected static int INT_e = 'e'; final protected static int INT_E = 'E'; final protected static char CHAR_NULL = '\0'; // Numeric value holders: multiple fields used for // for efficiency /** * Bitfield that indicates which numeric representations * have been calculated for the current type */ protected int _numTypesValid = NR_UNKNOWN; // First primitives protected int _numberInt; protected long _numberLong; protected double _numberDouble; // And then object types protected BigInteger _numberBigInt; protected BigDecimal _numberBigDecimal; // And then other information about value itself /** * Flag that indicates whether numeric value has a negative * value. That is, whether its textual representation starts * with minus character. */ protected boolean _numberNegative; /** * Length of integer part of the number, in characters */ protected int _intLength; /** * Length of the fractional part (not including decimal * point or exponent), in characters. * Not used for pure integer values. */ protected int _fractLength; /** * Length of the exponent part of the number, if any, not * including 'e' marker or sign, just digits. * Not used for pure integer values. */ protected int _expLength; /* /********************************************************** /* Life-cycle /********************************************************** */ protected JsonParserBase(IOContext ctxt, int features) { super(); _features = features; _ioContext = ctxt; _textBuffer = ctxt.constructTextBuffer(); _parsingContext = JsonReadContext.createRootContext(); } @Override public Version version() { return VersionUtil.versionFor(getClass()); } /* /********************************************************** /* JsonParser impl /********************************************************** */ /** * Method that can be called to get the name associated with * the current event. */ @Override public String getCurrentName() throws IOException, JsonParseException { // [JACKSON-395]: start markers require information from parent if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { JsonReadContext parent = _parsingContext.getParent(); return parent.getCurrentName(); } return _parsingContext.getCurrentName(); } @Override public void close() throws IOException { if (!_closed) { _closed = true; try { _closeInput(); } finally { // as per [JACKSON-324], do in finally block // Also, internal buffer(s) can now be released as well _releaseBuffers(); } } } @Override public boolean isClosed() { return _closed; } @Override public JsonReadContext getParsingContext() { return _parsingContext; } /** * Method that return the starting location of the current * token; that is, position of the first character from input * that starts the current token. */ @Override public JsonLocation getTokenLocation() { return new JsonLocation(_ioContext.getSourceReference(), getTokenCharacterOffset(), getTokenLineNr(), getTokenColumnNr()); } /** * Method that returns location of the last processed character; * usually for error reporting purposes */ @Override public JsonLocation getCurrentLocation() { int col = _inputPtr - _currInputRowStart + 1; // 1-based return new JsonLocation(_ioContext.getSourceReference(), _currInputProcessed + _inputPtr - 1, _currInputRow, col); } /* /********************************************************** /* Public API, access to token information, text /********************************************************** */ @Override public boolean hasTextCharacters() { if (_currToken == JsonToken.VALUE_STRING) { return true; // usually true } if (_currToken == JsonToken.FIELD_NAME) { return _nameCopied; } return false; } /* /********************************************************** /* Public low-level accessors /********************************************************** */ public final long getTokenCharacterOffset() { return _tokenInputTotal; } public final int getTokenLineNr() { return _tokenInputRow; } public final int getTokenColumnNr() { // note: value of -1 means "not available"; otherwise convert from 0-based to 1-based int col = _tokenInputCol; return (col < 0) ? col : (col + 1); } /* /********************************************************** /* Low-level reading, other /********************************************************** */ protected final void loadMoreGuaranteed() throws IOException { if (!loadMore()) { _reportInvalidEOF(); } } /* /********************************************************** /* Abstract methods needed from sub-classes /********************************************************** */ protected abstract boolean loadMore() throws IOException; protected abstract void _finishString() throws IOException, JsonParseException; protected abstract void _closeInput() throws IOException; protected abstract byte[] _decodeBase64(Base64Variant b64variant) throws IOException, JsonParseException; /* /********************************************************** /* Low-level reading, other /********************************************************** */ /** * Method called to release internal buffers owned by the base * reader. This may be called along with {@link #_closeInput} (for * example, when explicitly closing this reader instance), or * separately (if need be). */ protected void _releaseBuffers() throws IOException { _textBuffer.releaseBuffers(); char[] buf = _nameCopyBuffer; if (buf != null) { _nameCopyBuffer = null; _ioContext.releaseNameCopyBuffer(buf); } } /** * Method called when an EOF is encountered between tokens. * If so, it may be a legitimate EOF, but only iff there * is no open non-root context. */ @Override protected void _handleEOF() throws JsonParseException { if (!_parsingContext.inRoot()) { _reportInvalidEOF(": expected close marker for "+_parsingContext.getTypeDesc()+" (from "+_parsingContext.getStartLocation(_ioContext.getSourceReference())+")"); } } /* /********************************************************** /* Internal/package methods: Error reporting /********************************************************** */ protected void _reportMismatchedEndMarker(int actCh, char expCh) throws JsonParseException { String startDesc = ""+_parsingContext.getStartLocation(_ioContext.getSourceReference()); _reportError("Unexpected close marker '"+((char) actCh)+"': expected '"+expCh+"' (for "+_parsingContext.getTypeDesc()+" starting at "+startDesc+")"); } /* /********************************************************** /* Internal/package methods: shared/reusable builders /********************************************************** */ public ByteArrayBuilder _getByteArrayBuilder() { if (_byteArrayBuilder == null) { _byteArrayBuilder = new ByteArrayBuilder(); } else { _byteArrayBuilder.reset(); } return _byteArrayBuilder; } /* /********************************************************** /* Methods from former JsonNumericParserBase /********************************************************** */ // // // Life-cycle of number-parsing protected final JsonToken reset(boolean negative, int intLen, int fractLen, int expLen) { if (fractLen < 1 && expLen < 1) { // integer return resetInt(negative, intLen); } return resetFloat(negative, intLen, fractLen, expLen); } protected final JsonToken resetInt(boolean negative, int intLen) { _numberNegative = negative; _intLength = intLen; _fractLength = 0; _expLength = 0; _numTypesValid = NR_UNKNOWN; // to force parsing return JsonToken.VALUE_NUMBER_INT; } protected final JsonToken resetFloat(boolean negative, int intLen, int fractLen, int expLen) { _numberNegative = negative; _intLength = intLen; _fractLength = fractLen; _expLength = expLen; _numTypesValid = NR_UNKNOWN; // to force parsing return JsonToken.VALUE_NUMBER_FLOAT; } protected final JsonToken resetAsNaN(String valueStr, double value) { _textBuffer.resetWithString(valueStr); _numberDouble = value; _numTypesValid = NR_DOUBLE; return JsonToken.VALUE_NUMBER_FLOAT; } /* /********************************************************** /* Numeric accessors of public API /********************************************************** */ @Override public Number getNumberValue() throws IOException, JsonParseException { if (_numTypesValid == NR_UNKNOWN) { _parseNumericValue(NR_UNKNOWN); // will also check event type } // Separate types for int types if (_currToken == JsonToken.VALUE_NUMBER_INT) { if ((_numTypesValid & NR_INT) != 0) { return Integer.valueOf(_numberInt); } if ((_numTypesValid & NR_LONG) != 0) { return Long.valueOf(_numberLong); } if ((_numTypesValid & NR_BIGINT) != 0) { return _numberBigInt; } // Shouldn't get this far but if we do return _numberBigDecimal; } /* And then floating point types. But here optimal type * needs to be big decimal, to avoid losing any data? */ if ((_numTypesValid & NR_BIGDECIMAL) != 0) { return _numberBigDecimal; } if ((_numTypesValid & NR_DOUBLE) == 0) { // sanity check _throwInternal(); } return Double.valueOf(_numberDouble); } @Override public NumberType getNumberType() throws IOException, JsonParseException { if (_numTypesValid == NR_UNKNOWN) { _parseNumericValue(NR_UNKNOWN); // will also check event type } if (_currToken == JsonToken.VALUE_NUMBER_INT) { if ((_numTypesValid & NR_INT) != 0) { return NumberType.INT; } if ((_numTypesValid & NR_LONG) != 0) { return NumberType.LONG; } return NumberType.BIG_INTEGER; } /* And then floating point types. Here optimal type * needs to be big decimal, to avoid losing any data? * However... using BD is slow, so let's allow returning * double as type if no explicit call has been made to access * data as BD? */ if ((_numTypesValid & NR_BIGDECIMAL) != 0) { return NumberType.BIG_DECIMAL; } return NumberType.DOUBLE; } @Override public int getIntValue() throws IOException, JsonParseException { if ((_numTypesValid & NR_INT) == 0) { if (_numTypesValid == NR_UNKNOWN) { // not parsed at all _parseNumericValue(NR_INT); // will also check event type } if ((_numTypesValid & NR_INT) == 0) { // wasn't an int natively? convertNumberToInt(); // let's make it so, if possible } } return _numberInt; } @Override public long getLongValue() throws IOException, JsonParseException { if ((_numTypesValid & NR_LONG) == 0) { if (_numTypesValid == NR_UNKNOWN) { _parseNumericValue(NR_LONG); } if ((_numTypesValid & NR_LONG) == 0) { convertNumberToLong(); } } return _numberLong; } @Override public BigInteger getBigIntegerValue() throws IOException, JsonParseException { if ((_numTypesValid & NR_BIGINT) == 0) { if (_numTypesValid == NR_UNKNOWN) { _parseNumericValue(NR_BIGINT); } if ((_numTypesValid & NR_BIGINT) == 0) { convertNumberToBigInteger(); } } return _numberBigInt; } @Override public float getFloatValue() throws IOException, JsonParseException { double value = getDoubleValue(); /* 22-Jan-2009, tatu: Bounds/range checks would be tricky * here, so let's not bother even trying... */ /* if (value < -Float.MAX_VALUE || value > MAX_FLOAT_D) { _reportError("Numeric value ("+getText()+") out of range of Java float"); } */ return (float) value; } @Override public double getDoubleValue() throws IOException, JsonParseException { if ((_numTypesValid & NR_DOUBLE) == 0) { if (_numTypesValid == NR_UNKNOWN) { _parseNumericValue(NR_DOUBLE); } if ((_numTypesValid & NR_DOUBLE) == 0) { convertNumberToDouble(); } } return _numberDouble; } @Override public BigDecimal getDecimalValue() throws IOException, JsonParseException { if ((_numTypesValid & NR_BIGDECIMAL) == 0) { if (_numTypesValid == NR_UNKNOWN) { _parseNumericValue(NR_BIGDECIMAL); } if ((_numTypesValid & NR_BIGDECIMAL) == 0) { convertNumberToBigDecimal(); } } return _numberBigDecimal; } /* /********************************************************** /* Conversion from textual to numeric representation /********************************************************** */ /** * Method that will parse actual numeric value out of a syntactically * valid number value. Type it will parse into depends on whether * it is a floating point number, as well as its magnitude: smallest * legal type (of ones available) is used for efficiency. * * @param expType Numeric type that we will immediately need, if any; * mostly necessary to optimize handling of floating point numbers */ protected void _parseNumericValue(int expType) throws IOException, JsonParseException { // Int or float? if (_currToken == JsonToken.VALUE_NUMBER_INT) { char[] buf = _textBuffer.getTextBuffer(); int offset = _textBuffer.getTextOffset(); int len = _intLength; if (_numberNegative) { ++offset; } if (len <= 9) { // definitely fits in int int i = NumberInput.parseInt(buf, offset, len); _numberInt = _numberNegative ? -i : i; _numTypesValid = NR_INT; return; } if (len <= 18) { // definitely fits AND is easy to parse using 2 int parse calls long l = NumberInput.parseLong(buf, offset, len); if (_numberNegative) { l = -l; } // [JACKSON-230] Could still fit in int, need to check if (len == 10) { if (_numberNegative) { if (l >= MIN_INT_L) { _numberInt = (int) l; _numTypesValid = NR_INT; return; } } else { if (l <= MAX_INT_L) { _numberInt = (int) l; _numTypesValid = NR_INT; return; } } } _numberLong = l; _numTypesValid = NR_LONG; return; } _parseSlowIntValue(expType, buf, offset, len); return; } if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) { _parseSlowFloatValue(expType); return; } _reportError("Current token ("+_currToken+") not numeric, can not use numeric value accessors"); } private final void _parseSlowFloatValue(int expType) throws IOException, JsonParseException { /* Nope: floating point. Here we need to be careful to get * optimal parsing strategy: choice is between accurate but * slow (BigDecimal) and lossy but fast (Double). For now * let's only use BD when explicitly requested -- it can * still be constructed correctly at any point since we do * retain textual representation */ try { if (expType == NR_BIGDECIMAL) { _numberBigDecimal = _textBuffer.contentsAsDecimal(); _numTypesValid = NR_BIGDECIMAL; } else { // Otherwise double has to do _numberDouble = _textBuffer.contentsAsDouble(); _numTypesValid = NR_DOUBLE; } } catch (NumberFormatException nex) { // Can this ever occur? Due to overflow, maybe? _wrapError("Malformed numeric value '"+_textBuffer.contentsAsString()+"'", nex); } } private final void _parseSlowIntValue(int expType, char[] buf, int offset, int len) throws IOException, JsonParseException { String numStr = _textBuffer.contentsAsString(); try { // [JACKSON-230] Some long cases still... if (NumberInput.inLongRange(buf, offset, len, _numberNegative)) { // Probably faster to construct a String, call parse, than to use BigInteger _numberLong = Long.parseLong(numStr); _numTypesValid = NR_LONG; } else { // nope, need the heavy guns... (rare case) _numberBigInt = new BigInteger(numStr); _numTypesValid = NR_BIGINT; } } catch (NumberFormatException nex) { // Can this ever occur? Due to overflow, maybe? _wrapError("Malformed numeric value '"+numStr+"'", nex); } } /* /********************************************************** /* Numeric conversions /********************************************************** */ protected void convertNumberToInt() throws IOException, JsonParseException { // First, converting from long ought to be easy if ((_numTypesValid & NR_LONG) != 0) { // Let's verify it's lossless conversion by simple roundtrip int result = (int) _numberLong; if (((long) result) != _numberLong) { _reportError("Numeric value ("+getText()+") out of range of int"); } _numberInt = result; } else if ((_numTypesValid & NR_BIGINT) != 0) { // !!! Should check for range... _numberInt = _numberBigInt.intValue(); } else if ((_numTypesValid & NR_DOUBLE) != 0) { // Need to check boundaries if (_numberDouble < MIN_INT_D || _numberDouble > MAX_INT_D) { reportOverflowInt(); } _numberInt = (int) _numberDouble; } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { if (BD_MIN_INT.compareTo(_numberBigDecimal) > 0 || BD_MAX_INT.compareTo(_numberBigDecimal) < 0) { reportOverflowInt(); } _numberInt = _numberBigDecimal.intValue(); } else { _throwInternal(); // should never get here } _numTypesValid |= NR_INT; } protected void convertNumberToLong() throws IOException, JsonParseException { if ((_numTypesValid & NR_INT) != 0) { _numberLong = (long) _numberInt; } else if ((_numTypesValid & NR_BIGINT) != 0) { // !!! Should check for range... _numberLong = _numberBigInt.longValue(); } else if ((_numTypesValid & NR_DOUBLE) != 0) { // Need to check boundaries if (_numberDouble < MIN_LONG_D || _numberDouble > MAX_LONG_D) { reportOverflowLong(); } _numberLong = (long) _numberDouble; } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { if (BD_MIN_LONG.compareTo(_numberBigDecimal) > 0 || BD_MAX_LONG.compareTo(_numberBigDecimal) < 0) { reportOverflowLong(); } _numberLong = _numberBigDecimal.longValue(); } else { _throwInternal(); // should never get here } _numTypesValid |= NR_LONG; } protected void convertNumberToBigInteger() throws IOException, JsonParseException { if ((_numTypesValid & NR_BIGDECIMAL) != 0) { // here it'll just get truncated, no exceptions thrown _numberBigInt = _numberBigDecimal.toBigInteger(); } else if ((_numTypesValid & NR_LONG) != 0) { _numberBigInt = BigInteger.valueOf(_numberLong); } else if ((_numTypesValid & NR_INT) != 0) { _numberBigInt = BigInteger.valueOf(_numberInt); } else if ((_numTypesValid & NR_DOUBLE) != 0) { _numberBigInt = BigDecimal.valueOf(_numberDouble).toBigInteger(); } else { _throwInternal(); // should never get here } _numTypesValid |= NR_BIGINT; } protected void convertNumberToDouble() throws IOException, JsonParseException { /* 05-Aug-2008, tatus: Important note: this MUST start with * more accurate representations, since we don't know which * value is the original one (others get generated when * requested) */ if ((_numTypesValid & NR_BIGDECIMAL) != 0) { _numberDouble = _numberBigDecimal.doubleValue(); } else if ((_numTypesValid & NR_BIGINT) != 0) { _numberDouble = _numberBigInt.doubleValue(); } else if ((_numTypesValid & NR_LONG) != 0) { _numberDouble = (double) _numberLong; } else if ((_numTypesValid & NR_INT) != 0) { _numberDouble = (double) _numberInt; } else { _throwInternal(); // should never get here } _numTypesValid |= NR_DOUBLE; } protected void convertNumberToBigDecimal() throws IOException, JsonParseException { /* 05-Aug-2008, tatus: Important note: this MUST start with * more accurate representations, since we don't know which * value is the original one (others get generated when * requested) */ if ((_numTypesValid & NR_DOUBLE) != 0) { /* Let's actually parse from String representation, * to avoid rounding errors that non-decimal floating operations * would incur */ _numberBigDecimal = new BigDecimal(getText()); } else if ((_numTypesValid & NR_BIGINT) != 0) { _numberBigDecimal = new BigDecimal(_numberBigInt); } else if ((_numTypesValid & NR_LONG) != 0) { _numberBigDecimal = BigDecimal.valueOf(_numberLong); } else if ((_numTypesValid & NR_INT) != 0) { _numberBigDecimal = BigDecimal.valueOf((long) _numberInt); } else { _throwInternal(); // should never get here } _numTypesValid |= NR_BIGDECIMAL; } /* /********************************************************** /* Number handling exceptions /********************************************************** */ protected void reportUnexpectedNumberChar(int ch, String comment) throws JsonParseException { String msg = "Unexpected character ("+_getCharDesc(ch)+") in numeric value"; if (comment != null) { msg += ": "+comment; } _reportError(msg); } protected void reportInvalidNumber(String msg) throws JsonParseException { _reportError("Invalid numeric value: "+msg); } protected void reportOverflowInt() throws IOException, JsonParseException { _reportError("Numeric value ("+getText()+") out of range of int ("+Integer.MIN_VALUE+" - "+Integer.MAX_VALUE+")"); } protected void reportOverflowLong() throws IOException, JsonParseException { _reportError("Numeric value ("+getText()+") out of range of long ("+Long.MIN_VALUE+" - "+Long.MAX_VALUE+")"); } /* /********************************************************** /* Base64 handling support /********************************************************** */ /** * Method that sub-classes must implement to support escaped sequences * in base64-encoded sections. * Sub-classes that do not need base64 support can leave this as is */ protected char _decodeEscaped() throws IOException, JsonParseException { throw new UnsupportedOperationException(); } protected final int _decodeBase64Escape(Base64Variant b64variant, int ch, int index) throws IOException, JsonParseException { // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars if (ch != '\\') { throw reportInvalidBase64Char(b64variant, ch, index); } int unescaped = _decodeEscaped(); // if white space, skip if first triplet; otherwise errors if (unescaped <= INT_SPACE) { if (index == 0) { // whitespace only allowed to be skipped between triplets return -1; } } // otherwise try to find actual triplet value int bits = b64variant.decodeBase64Char(unescaped); if (bits < 0) { throw reportInvalidBase64Char(b64variant, unescaped, index); } return bits; } protected final int _decodeBase64Escape(Base64Variant b64variant, char ch, int index) throws IOException, JsonParseException { // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars if (ch != '\\') { throw reportInvalidBase64Char(b64variant, ch, index); } char unescaped = _decodeEscaped(); // if white space, skip if first triplet; otherwise errors if (unescaped <= INT_SPACE) { if (index == 0) { // whitespace only allowed to be skipped between triplets return -1; } } // otherwise try to find actual triplet value int bits = b64variant.decodeBase64Char(unescaped); if (bits < 0) { throw reportInvalidBase64Char(b64variant, unescaped, index); } return bits; } protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex) throws IllegalArgumentException { return reportInvalidBase64Char(b64variant, ch, bindex, null); } /** * @param bindex Relative index within base64 character unit; between 0 * and 3 (as unit has exactly 4 characters) */ protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex, String msg) throws IllegalArgumentException { String base; if (ch <= INT_SPACE) { base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units"; } else if (b64variant.usesPaddingChar(ch)) { base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character"; } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) { // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level) base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content"; } else { base = "Illegal character '"+((char)ch)+"' (code 0x"+Integer.toHexString(ch)+") in base64 content"; } if (msg != null) { base = base + ": " + msg; } return new IllegalArgumentException(base); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/ReaderBasedParserBase.java0000644000175000017500000001505411655120726030063 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.io.IOContext; /** * This is a simple low-level input reader base class, used by * JSON parser. * The reason for sub-classing (over composition) * is due to need for direct access to character buffers * and positions. * * @author Tatu Saloranta * * @deprecated Since 1.9 sub-classes should just include code * from here as is. */ @Deprecated public abstract class ReaderBasedParserBase extends JsonParserBase { /* /********************************************************** /* Configuration /********************************************************** */ /** * Reader that can be used for reading more content, if one * buffer from input source, but in some cases pre-loaded buffer * is handed to the parser. */ protected Reader _reader; /* /********************************************************** /* Current input data /********************************************************** */ /** * Current buffer from which data is read; generally data is read into * buffer from input source. */ protected char[] _inputBuffer; /* /********************************************************** /* Life-cycle /********************************************************** */ protected ReaderBasedParserBase(IOContext ctxt, int features, Reader r) { super(ctxt, features); _reader = r; _inputBuffer = ctxt.allocTokenBuffer(); } /* /********************************************************** /* Overrides /********************************************************** */ @Override public int releaseBuffered(Writer w) throws IOException { int count = _inputEnd - _inputPtr; if (count < 1) { return 0; } // let's just advance ptr to end int origPtr = _inputPtr; w.write(_inputBuffer, origPtr, count); return count; } @Override public Object getInputSource() { return _reader; } /* /********************************************************** /* Low-level reading, other /********************************************************** */ @Override protected final boolean loadMore() throws IOException { _currInputProcessed += _inputEnd; _currInputRowStart -= _inputEnd; if (_reader != null) { int count = _reader.read(_inputBuffer, 0, _inputBuffer.length); if (count > 0) { _inputPtr = 0; _inputEnd = count; return true; } // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd); } } return false; } protected char getNextChar(String eofMsg) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(eofMsg); } } return _inputBuffer[_inputPtr++]; } @Override protected void _closeInput() throws IOException { /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying Reader, unless we "own" it, or auto-closing * feature is enabled. * One downside is that when using our optimized * Reader (granted, we only do that for UTF-32...) this * means that buffer recycling won't work correctly. */ if (_reader != null) { if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) { _reader.close(); } _reader = null; } } /** * Method called to release internal buffers owned by the base * reader. This may be called along with {@link #_closeInput} (for * example, when explicitly closing this reader instance), or * separately (if need be). */ @Override protected void _releaseBuffers() throws IOException { super._releaseBuffers(); char[] buf = _inputBuffer; if (buf != null) { _inputBuffer = null; _ioContext.releaseTokenBuffer(buf); } } /* /********************************************************** /* Helper methods for subclasses /********************************************************** */ /** * Helper method for checking whether input matches expected token * * @since 1.8 */ protected final boolean _matchToken(String matchStr, int i) throws IOException, JsonParseException { final int len = matchStr.length(); do { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOFInValue(); } } if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) { _reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN"); } ++_inputPtr; } while (++i < len); // but let's also ensure we either get EOF, or non-alphanum char... if (_inputPtr >= _inputEnd) { if (!loadMore()) { return true; } } char c = _inputBuffer[_inputPtr]; // if Java letter, it's a problem tho if (Character.isJavaIdentifierPart(c)) { ++_inputPtr; _reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN"); } return true; } protected void _reportInvalidToken(String matchedPart, String msg) throws IOException, JsonParseException { StringBuilder sb = new StringBuilder(matchedPart); /* Let's just try to find what appears to be the token, using * regular Java identifier character rules. It's just a heuristic, * nothing fancy here. */ while (true) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { break; } } char c = _inputBuffer[_inputPtr]; if (!Character.isJavaIdentifierPart(c)) { break; } ++_inputPtr; sb.append(c); } _reportError("Unrecognized token '"+sb.toString()+"': was expecting "); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/package-info.java0000644000175000017500000000030311655120726026265 0ustar jamespagejamespage/** * Parser and generator implementation classes that Jackson * defines and uses. * Application code should not (need to) use contents of this package. */ package org.codehaus.jackson.impl; jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/Utf8StreamParser.java0000644000175000017500000030751211655120726027134 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.io.IOContext; import org.codehaus.jackson.sym.*; import org.codehaus.jackson.util.*; /** * This is a concrete implementation of {@link JsonParser}, which is * based on a {@link java.io.InputStream} as the input source. */ public final class Utf8StreamParser extends JsonParserBase { final static byte BYTE_LF = (byte) '\n'; private final static int[] sInputCodesUtf8 = CharTypes.getInputCodeUtf8(); /** * Latin1 encoding is not supported, but we do use 8-bit subset for * pre-processing task, to simplify first pass, keep it fast. */ private final static int[] sInputCodesLatin1 = CharTypes.getInputCodeLatin1(); /* /********************************************************** /* Configuration /********************************************************** */ /** * Codec used for data binding when (if) requested; typically full * ObjectMapper, but that abstract is not part of core * package. */ protected ObjectCodec _objectCodec; /** * Symbol table that contains field names encountered so far */ final protected BytesToNameCanonicalizer _symbols; /* /********************************************************** /* Parsing state /********************************************************** */ /** * Temporary buffer used for name parsing. */ protected int[] _quadBuffer = new int[16]; /** * Flag that indicates that the current token has not yet * been fully processed, and needs to be finished for * some access (or skipped to obtain the next token) */ protected boolean _tokenIncomplete = false; /** * Temporary storage for partially parsed name bytes. */ private int _quad1; /* /********************************************************** /* Input buffering (from former 'StreamBasedParserBase') /********************************************************** */ protected InputStream _inputStream; /* /********************************************************** /* Current input data /********************************************************** */ /** * Current buffer from which data is read; generally data is read into * buffer from input source, but in some cases pre-loaded buffer * is handed to the parser. */ protected byte[] _inputBuffer; /** * Flag that indicates whether the input buffer is recycable (and * needs to be returned to recycler once we are done) or not. *

* If it is not, it also means that parser can NOT modify underlying * buffer. */ protected boolean _bufferRecyclable; /* /********************************************************** /* Life-cycle /********************************************************** */ public Utf8StreamParser(IOContext ctxt, int features, InputStream in, ObjectCodec codec, BytesToNameCanonicalizer sym, byte[] inputBuffer, int start, int end, boolean bufferRecyclable) { super(ctxt, features); _inputStream = in; _objectCodec = codec; _symbols = sym; _inputBuffer = inputBuffer; _inputPtr = start; _inputEnd = end; _bufferRecyclable = bufferRecyclable; // 12-Mar-2010, tatus: Sanity check, related to [JACKSON-259]: if (!JsonParser.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(features)) { // should never construct non-canonical UTF-8/byte parser (instead, use Reader) _throwInternal(); } } @Override public ObjectCodec getCodec() { return _objectCodec; } @Override public void setCodec(ObjectCodec c) { _objectCodec = c; } /* /********************************************************** /* Former StreamBasedParserBase methods /********************************************************** */ @Override public int releaseBuffered(OutputStream out) throws IOException { int count = _inputEnd - _inputPtr; if (count < 1) { return 0; } // let's just advance ptr to end int origPtr = _inputPtr; out.write(_inputBuffer, origPtr, count); return count; } @Override public Object getInputSource() { return _inputStream; } /* /********************************************************** /* Low-level reading, other /********************************************************** */ @Override protected final boolean loadMore() throws IOException { _currInputProcessed += _inputEnd; _currInputRowStart -= _inputEnd; if (_inputStream != null) { int count = _inputStream.read(_inputBuffer, 0, _inputBuffer.length); if (count > 0) { _inputPtr = 0; _inputEnd = count; return true; } // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes"); } } return false; } /** * Helper method that will try to load at least specified number bytes in * input buffer, possible moving existing data around if necessary * * @since 1.6 */ protected final boolean _loadToHaveAtLeast(int minAvailable) throws IOException { // No input stream, no leading (either we are closed, or have non-stream input source) if (_inputStream == null) { return false; } // Need to move remaining data in front? int amount = _inputEnd - _inputPtr; if (amount > 0 && _inputPtr > 0) { _currInputProcessed += _inputPtr; _currInputRowStart -= _inputPtr; System.arraycopy(_inputBuffer, _inputPtr, _inputBuffer, 0, amount); _inputEnd = amount; } else { _inputEnd = 0; } _inputPtr = 0; while (_inputEnd < minAvailable) { int count = _inputStream.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd); if (count < 1) { // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("InputStream.read() returned 0 characters when trying to read "+amount+" bytes"); } return false; } _inputEnd += count; } return true; } @Override protected void _closeInput() throws IOException { /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying InputStream, unless we "own" it, or auto-closing * feature is enabled. */ if (_inputStream != null) { if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) { _inputStream.close(); } _inputStream = null; } } /** * Method called to release internal buffers owned by the base * reader. This may be called along with {@link #_closeInput} (for * example, when explicitly closing this reader instance), or * separately (if need be). */ @Override protected void _releaseBuffers() throws IOException { super._releaseBuffers(); if (_bufferRecyclable) { byte[] buf = _inputBuffer; if (buf != null) { _inputBuffer = null; _ioContext.releaseReadIOBuffer(buf); } } } /* /********************************************************** /* Public API, data access /********************************************************** */ @Override public String getText() throws IOException, JsonParseException { JsonToken t = _currToken; if (t == JsonToken.VALUE_STRING) { if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } return _textBuffer.contentsAsString(); } return _getText2(t); } protected final String _getText2(JsonToken t) { if (t == null) { return null; } switch (t) { case FIELD_NAME: return _parsingContext.getCurrentName(); case VALUE_STRING: // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.contentsAsString(); } return t.asString(); } @Override public char[] getTextCharacters() throws IOException, JsonParseException { if (_currToken != null) { // null only before/after document switch (_currToken) { case FIELD_NAME: if (!_nameCopied) { String name = _parsingContext.getCurrentName(); int nameLen = name.length(); if (_nameCopyBuffer == null) { _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen); } else if (_nameCopyBuffer.length < nameLen) { _nameCopyBuffer = new char[nameLen]; } name.getChars(0, nameLen, _nameCopyBuffer, 0); _nameCopied = true; } return _nameCopyBuffer; case VALUE_STRING: if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.getTextBuffer(); default: return _currToken.asCharArray(); } } return null; } @Override public int getTextLength() throws IOException, JsonParseException { if (_currToken != null) { // null only before/after document switch (_currToken) { case FIELD_NAME: return _parsingContext.getCurrentName().length(); case VALUE_STRING: if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.size(); default: return _currToken.asCharArray().length; } } return 0; } @Override public int getTextOffset() throws IOException, JsonParseException { // Most have offset of 0, only some may have other values: if (_currToken != null) { switch (_currToken) { case FIELD_NAME: return 0; case VALUE_STRING: if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.getTextOffset(); } } return 0; } @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { if (_currToken != JsonToken.VALUE_STRING && (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) { _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary"); } /* To ensure that we won't see inconsistent data, better clear up * state... */ if (_tokenIncomplete) { try { _binaryValue = _decodeBase64(b64variant); } catch (IllegalArgumentException iae) { throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage()); } /* let's clear incomplete only now; allows for accessing other * textual content in error cases */ _tokenIncomplete = false; } return _binaryValue; } /* /********************************************************** /* Public API, traversal, basic /********************************************************** */ /** * @return Next token from the stream, if any found, or null * to indicate end-of-input */ @Override public JsonToken nextToken() throws IOException, JsonParseException { _numTypesValid = NR_UNKNOWN; /* First: field names are special -- we will always tokenize * (part of) value along with field name to simplify * state handling. If so, can and need to use secondary token: */ if (_currToken == JsonToken.FIELD_NAME) { return _nextAfterName(); } if (_tokenIncomplete) { _skipString(); // only strings can be partial } int i = _skipWSOrEnd(); if (i < 0) { // end-of-input /* 19-Feb-2009, tatu: Should actually close/release things * like input source, symbol table and recyclable buffers now. */ close(); return (_currToken = null); } /* First, need to ensure we know the starting location of token * after skipping leading white space */ _tokenInputTotal = _currInputProcessed + _inputPtr - 1; _tokenInputRow = _currInputRow; _tokenInputCol = _inputPtr - _currInputRowStart - 1; // finally: clear any data retained so far _binaryValue = null; // Closing scope? if (i == INT_RBRACKET) { if (!_parsingContext.inArray()) { _reportMismatchedEndMarker(i, '}'); } _parsingContext = _parsingContext.getParent(); return (_currToken = JsonToken.END_ARRAY); } if (i == INT_RCURLY) { if (!_parsingContext.inObject()) { _reportMismatchedEndMarker(i, ']'); } _parsingContext = _parsingContext.getParent(); return (_currToken = JsonToken.END_OBJECT); } // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { if (i != INT_COMMA) { _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries"); } i = _skipWS(); } /* And should we now have a name? Always true for * Object contexts, since the intermediate 'expect-value' * state is never retained. */ if (!_parsingContext.inObject()) { return _nextTokenNotInObject(i); } // So first parse the field name itself: Name n = _parseFieldName(i); _parsingContext.setCurrentName(n.getName()); _currToken = JsonToken.FIELD_NAME; i = _skipWS(); if (i != INT_COLON) { _reportUnexpectedChar(i, "was expecting a colon to separate field name and value"); } i = _skipWS(); // Ok: we must have a value... what is it? Strings are very common, check first: if (i == INT_QUOTE) { _tokenIncomplete = true; _nextToken = JsonToken.VALUE_STRING; return _currToken; } JsonToken t; switch (i) { case INT_LBRACKET: t = JsonToken.START_ARRAY; break; case INT_LCURLY: t = JsonToken.START_OBJECT; break; case INT_RBRACKET: case INT_RCURLY: // Error: neither is valid at this point; valid closers have // been handled earlier _reportUnexpectedChar(i, "expected a value"); case INT_t: _matchToken("true", 1); t = JsonToken.VALUE_TRUE; break; case INT_f: _matchToken("false", 1); t = JsonToken.VALUE_FALSE; break; case INT_n: _matchToken("null", 1); t = JsonToken.VALUE_NULL; break; case INT_MINUS: /* Should we have separate handling for plus? Although * it is not allowed per se, it may be erroneously used, * and could be indicate by a more specific error message. */ case INT_0: case INT_1: case INT_2: case INT_3: case INT_4: case INT_5: case INT_6: case INT_7: case INT_8: case INT_9: t = parseNumberText(i); break; default: t = _handleUnexpectedValue(i); } _nextToken = t; return _currToken; } private final JsonToken _nextTokenNotInObject(int i) throws IOException, JsonParseException { if (i == INT_QUOTE) { _tokenIncomplete = true; return (_currToken = JsonToken.VALUE_STRING); } switch (i) { case INT_LBRACKET: _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); return (_currToken = JsonToken.START_ARRAY); case INT_LCURLY: _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); return (_currToken = JsonToken.START_OBJECT); case INT_RBRACKET: case INT_RCURLY: // Error: neither is valid at this point; valid closers have // been handled earlier _reportUnexpectedChar(i, "expected a value"); case INT_t: _matchToken("true", 1); return (_currToken = JsonToken.VALUE_TRUE); case INT_f: _matchToken("false", 1); return (_currToken = JsonToken.VALUE_FALSE); case INT_n: _matchToken("null", 1); return (_currToken = JsonToken.VALUE_NULL); case INT_MINUS: /* Should we have separate handling for plus? Although * it is not allowed per se, it may be erroneously used, * and could be indicate by a more specific error message. */ case INT_0: case INT_1: case INT_2: case INT_3: case INT_4: case INT_5: case INT_6: case INT_7: case INT_8: case INT_9: return (_currToken = parseNumberText(i)); } return (_currToken = _handleUnexpectedValue(i)); } private final JsonToken _nextAfterName() { _nameCopied = false; // need to invalidate if it was copied JsonToken t = _nextToken; _nextToken = null; // Also: may need to start new context? if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return (_currToken = t); } @Override public void close() throws IOException { super.close(); // Merge found symbols, if any: _symbols.release(); } /* /********************************************************** /* Public API, traversal, nextXxxValue/nextFieldName /********************************************************** */ @Override public boolean nextFieldName(SerializableString str) throws IOException, JsonParseException { // // // Note: most of code below is copied from nextToken() _numTypesValid = NR_UNKNOWN; if (_currToken == JsonToken.FIELD_NAME) { // can't have name right after name _nextAfterName(); return false; } if (_tokenIncomplete) { _skipString(); } int i = _skipWSOrEnd(); if (i < 0) { // end-of-input close(); _currToken = null; return false; } _tokenInputTotal = _currInputProcessed + _inputPtr - 1; _tokenInputRow = _currInputRow; _tokenInputCol = _inputPtr - _currInputRowStart - 1; // finally: clear any data retained so far _binaryValue = null; // Closing scope? if (i == INT_RBRACKET) { if (!_parsingContext.inArray()) { _reportMismatchedEndMarker(i, '}'); } _parsingContext = _parsingContext.getParent(); _currToken = JsonToken.END_ARRAY; return false; } if (i == INT_RCURLY) { if (!_parsingContext.inObject()) { _reportMismatchedEndMarker(i, ']'); } _parsingContext = _parsingContext.getParent(); _currToken = JsonToken.END_OBJECT; return false; } // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { if (i != INT_COMMA) { _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries"); } i = _skipWS(); } if (!_parsingContext.inObject()) { _nextTokenNotInObject(i); return false; } // // // This part differs, name parsing if (i == INT_QUOTE) { // when doing literal match, must consider escaping: byte[] nameBytes = str.asQuotedUTF8(); final int len = nameBytes.length; if ((_inputPtr + len) < _inputEnd) { // maybe... // first check length match by final int end = _inputPtr+len; if (_inputBuffer[end] == INT_QUOTE) { int offset = 0; final int ptr = _inputPtr; while (true) { if (offset == len) { // yes, match! _inputPtr = end+1; // skip current value first // First part is simple; setting of name _parsingContext.setCurrentName(str.getValue()); _currToken = JsonToken.FIELD_NAME; // But then we also must handle following value etc _isNextTokenNameYes(); return true; } if (nameBytes[offset] != _inputBuffer[ptr+offset]) { break; } ++offset; } } } } _isNextTokenNameNo(i); return false; } private final void _isNextTokenNameYes() throws IOException, JsonParseException { // very first thing: common case, colon, value, no white space int i; if (_inputPtr < _inputEnd && _inputBuffer[_inputPtr] == INT_COLON) { // fast case first ++_inputPtr; i = _inputBuffer[_inputPtr++]; if (i == INT_QUOTE) { _tokenIncomplete = true; _nextToken = JsonToken.VALUE_STRING; return; } if (i == INT_LCURLY) { _nextToken = JsonToken.START_OBJECT; return; } if (i == INT_LBRACKET) { _nextToken = JsonToken.START_ARRAY; return; } i &= 0xFF; if (i <= INT_SPACE || i == INT_SLASH) { --_inputPtr; i = _skipWS(); } } else { i = _skipColon(); } switch (i) { case INT_QUOTE: _tokenIncomplete = true; _nextToken = JsonToken.VALUE_STRING; return; case INT_LBRACKET: _nextToken = JsonToken.START_ARRAY; return; case INT_LCURLY: _nextToken = JsonToken.START_OBJECT; return; case INT_RBRACKET: case INT_RCURLY: _reportUnexpectedChar(i, "expected a value"); case INT_t: _matchToken("true", 1); _nextToken = JsonToken.VALUE_TRUE; return; case INT_f: _matchToken("false", 1); _nextToken = JsonToken.VALUE_FALSE; return; case INT_n: _matchToken("null", 1); _nextToken = JsonToken.VALUE_NULL; return; case INT_MINUS: case INT_0: case INT_1: case INT_2: case INT_3: case INT_4: case INT_5: case INT_6: case INT_7: case INT_8: case INT_9: _nextToken = parseNumberText(i); return; } _nextToken = _handleUnexpectedValue(i); } private final void _isNextTokenNameNo(int i) throws IOException, JsonParseException { // // // and this is back to standard nextToken() Name n = _parseFieldName(i); _parsingContext.setCurrentName(n.getName()); _currToken = JsonToken.FIELD_NAME; i = _skipWS(); if (i != INT_COLON) { _reportUnexpectedChar(i, "was expecting a colon to separate field name and value"); } i = _skipWS(); // Ok: we must have a value... what is it? Strings are very common, check first: if (i == INT_QUOTE) { _tokenIncomplete = true; _nextToken = JsonToken.VALUE_STRING; return; } JsonToken t; switch (i) { case INT_LBRACKET: t = JsonToken.START_ARRAY; break; case INT_LCURLY: t = JsonToken.START_OBJECT; break; case INT_RBRACKET: case INT_RCURLY: _reportUnexpectedChar(i, "expected a value"); case INT_t: _matchToken("true", 1); t = JsonToken.VALUE_TRUE; break; case INT_f: _matchToken("false", 1); t = JsonToken.VALUE_FALSE; break; case INT_n: _matchToken("null", 1); t = JsonToken.VALUE_NULL; break; case INT_MINUS: case INT_0: case INT_1: case INT_2: case INT_3: case INT_4: case INT_5: case INT_6: case INT_7: case INT_8: case INT_9: t = parseNumberText(i); break; default: t = _handleUnexpectedValue(i); } _nextToken = t; } @Override public String nextTextValue() throws IOException, JsonParseException { // two distinct cases; either got name and we know next type, or 'other' if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName' _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_STRING) { if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); } return _textBuffer.contentsAsString(); } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return null; } // !!! TODO: optimize this case as well return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null; } @Override public int nextIntValue(int defaultValue) throws IOException, JsonParseException { // two distinct cases; either got name and we know next type, or 'other' if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName' _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_NUMBER_INT) { return getIntValue(); } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return defaultValue; } // !!! TODO: optimize this case as well return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue; } @Override public long nextLongValue(long defaultValue) throws IOException, JsonParseException { // two distinct cases; either got name and we know next type, or 'other' if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName' _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_NUMBER_INT) { return getLongValue(); } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return defaultValue; } // !!! TODO: optimize this case as well return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue; } @Override public Boolean nextBooleanValue() throws IOException, JsonParseException { // two distinct cases; either got name and we know next type, or 'other' if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName' _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_TRUE) { return Boolean.TRUE; } if (t == JsonToken.VALUE_FALSE) { return Boolean.FALSE; } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return null; } switch (nextToken()) { case VALUE_TRUE: return Boolean.TRUE; case VALUE_FALSE: return Boolean.FALSE; } return null; } /* /********************************************************** /* Internal methods, number parsing /* (note: in 1.6 and prior, part of "Utf8NumericParser" /********************************************************** */ /** * Initial parsing method for number values. It needs to be able * to parse enough input to be able to determine whether the * value is to be considered a simple integer value, or a more * generic decimal value: latter of which needs to be expressed * as a floating point number. The basic rule is that if the number * has no fractional or exponential part, it is an integer; otherwise * a floating point number. *

* Because much of input has to be processed in any case, no partial * parsing is done: all input text will be stored for further * processing. However, actual numeric value conversion will be * deferred, since it is usually the most complicated and costliest * part of processing. */ protected final JsonToken parseNumberText(int c) throws IOException, JsonParseException { char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int outPtr = 0; boolean negative = (c == INT_MINUS); // Need to prepend sign? if (negative) { outBuf[outPtr++] = '-'; // Must have something after sign too if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } c = (int) _inputBuffer[_inputPtr++] & 0xFF; // Note: must be followed by a digit if (c < INT_0 || c > INT_9) { return _handleInvalidNumberStart(c, true); } } // One special case: if first char is 0, must not be followed by a digit if (c == INT_0) { c = _verifyNoLeadingZeroes(); } // Ok: we can first just add digit we saw first: outBuf[outPtr++] = (char) c; int intLen = 1; // And then figure out how far we can read without further checks: int end = _inputPtr + outBuf.length; if (end > _inputEnd) { end = _inputEnd; } // With this, we have a nice and tight loop: while (true) { if (_inputPtr >= end) { // Long enough to be split across boundary, so: return _parserNumber2(outBuf, outPtr, negative, intLen); } c = (int) _inputBuffer[_inputPtr++] & 0xFF; if (c < INT_0 || c > INT_9) { break; } ++intLen; outBuf[outPtr++] = (char) c; } if (c == '.' || c == 'e' || c == 'E') { return _parseFloatText(outBuf, outPtr, c, negative, intLen); } --_inputPtr; // to push back trailing char (comma etc) _textBuffer.setCurrentLength(outPtr); // And there we have it! return resetInt(negative, intLen); } /** * Method called to handle parsing when input is split across buffer boundary * (or output is longer than segment used to store it) */ private final JsonToken _parserNumber2(char[] outBuf, int outPtr, boolean negative, int intPartLength) throws IOException, JsonParseException { // Ok, parse the rest while (true) { if (_inputPtr >= _inputEnd && !loadMore()) { _textBuffer.setCurrentLength(outPtr); return resetInt(negative, intPartLength); } int c = (int) _inputBuffer[_inputPtr++] & 0xFF; if (c > INT_9 || c < INT_0) { if (c == '.' || c == 'e' || c == 'E') { return _parseFloatText(outBuf, outPtr, c, negative, intPartLength); } break; } if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = (char) c; ++intPartLength; } --_inputPtr; // to push back trailing char (comma etc) _textBuffer.setCurrentLength(outPtr); // And there we have it! return resetInt(negative, intPartLength); } /** * Method called when we have seen one zero, and want to ensure * it is not followed by another */ private final int _verifyNoLeadingZeroes() throws IOException, JsonParseException { // Ok to have plain "0" if (_inputPtr >= _inputEnd && !loadMore()) { return INT_0; } int ch = _inputBuffer[_inputPtr] & 0xFF; // if not followed by a number (probably '.'); return zero as is, to be included if (ch < INT_0 || ch > INT_9) { return INT_0; } // [JACKSON-358]: we may want to allow them, after all... if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) { reportInvalidNumber("Leading zeroes not allowed"); } // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number) ++_inputPtr; // Leading zero to be skipped if (ch == INT_0) { while (_inputPtr < _inputEnd || loadMore()) { ch = _inputBuffer[_inputPtr] & 0xFF; if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero return INT_0; } ++_inputPtr; // skip previous zeroes if (ch != INT_0) { // followed by other number; return break; } } } return ch; } private final JsonToken _parseFloatText(char[] outBuf, int outPtr, int c, boolean negative, int integerPartLength) throws IOException, JsonParseException { int fractLen = 0; boolean eof = false; // And then see if we get other parts if (c == '.') { // yes, fraction outBuf[outPtr++] = (char) c; fract_loop: while (true) { if (_inputPtr >= _inputEnd && !loadMore()) { eof = true; break fract_loop; } c = (int) _inputBuffer[_inputPtr++] & 0xFF; if (c < INT_0 || c > INT_9) { break fract_loop; } ++fractLen; if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = (char) c; } // must be followed by sequence of ints, one minimum if (fractLen == 0) { reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); } } int expLen = 0; if (c == 'e' || c == 'E') { // exponent? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = (char) c; // Not optional, can require that we get one more char if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } c = (int) _inputBuffer[_inputPtr++] & 0xFF; // Sign indicator? if (c == '-' || c == '+') { if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = (char) c; // Likewise, non optional: if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } c = (int) _inputBuffer[_inputPtr++] & 0xFF; } exp_loop: while (c <= INT_9 && c >= INT_0) { ++expLen; if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = (char) c; if (_inputPtr >= _inputEnd && !loadMore()) { eof = true; break exp_loop; } c = (int) _inputBuffer[_inputPtr++] & 0xFF; } // must be followed by sequence of ints, one minimum if (expLen == 0) { reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit"); } } // Ok; unless we hit end-of-input, need to push last char read back if (!eof) { --_inputPtr; } _textBuffer.setCurrentLength(outPtr); // And there we have it! return resetFloat(negative, integerPartLength, fractLen, expLen); } /* /********************************************************** /* Internal methods, secondary parsing /********************************************************** */ protected final Name _parseFieldName(int i) throws IOException, JsonParseException { if (i != INT_QUOTE) { return _handleUnusualFieldName(i); } // First: can we optimize out bounds checks? if ((_inputPtr + 9) > _inputEnd) { // Need 8 chars, plus one trailing (quote) return slowParseFieldName(); } // If so, can also unroll loops nicely /* 25-Nov-2008, tatu: This may seem weird, but here we do * NOT want to worry about UTF-8 decoding. Rather, we'll * assume that part is ok (if not it will get caught * later on), and just handle quotes and backslashes here. */ final byte[] input = _inputBuffer; final int[] codes = sInputCodesLatin1; int q = input[_inputPtr++] & 0xFF; if (codes[q] == 0) { i = input[_inputPtr++] & 0xFF; if (codes[i] == 0) { q = (q << 8) | i; i = input[_inputPtr++] & 0xFF; if (codes[i] == 0) { q = (q << 8) | i; i = input[_inputPtr++] & 0xFF; if (codes[i] == 0) { q = (q << 8) | i; i = input[_inputPtr++] & 0xFF; if (codes[i] == 0) { _quad1 = q; return parseMediumFieldName(i, codes); } if (i == INT_QUOTE) { // one byte/char case or broken return findName(q, 4); } return parseFieldName(q, i, 4); } if (i == INT_QUOTE) { // one byte/char case or broken return findName(q, 3); } return parseFieldName(q, i, 3); } if (i == INT_QUOTE) { // one byte/char case or broken return findName(q, 2); } return parseFieldName(q, i, 2); } if (i == INT_QUOTE) { // one byte/char case or broken return findName(q, 1); } return parseFieldName(q, i, 1); } if (q == INT_QUOTE) { // special case, "" return BytesToNameCanonicalizer.getEmptyName(); } return parseFieldName(0, q, 0); // quoting or invalid char } protected final Name parseMediumFieldName(int q2, final int[] codes) throws IOException, JsonParseException { // Ok, got 5 name bytes so far int i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { // 5 bytes return findName(_quad1, q2, 1); } return parseFieldName(_quad1, q2, i, 1); // quoting or invalid char } q2 = (q2 << 8) | i; i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { // 6 bytes return findName(_quad1, q2, 2); } return parseFieldName(_quad1, q2, i, 2); } q2 = (q2 << 8) | i; i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { // 7 bytes return findName(_quad1, q2, 3); } return parseFieldName(_quad1, q2, i, 3); } q2 = (q2 << 8) | i; i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { // 8 bytes return findName(_quad1, q2, 4); } return parseFieldName(_quad1, q2, i, 4); } _quadBuffer[0] = _quad1; _quadBuffer[1] = q2; return parseLongFieldName(i); } protected Name parseLongFieldName(int q) throws IOException, JsonParseException { // As explained above, will ignore UTF-8 encoding at this point final int[] codes = sInputCodesLatin1; int qlen = 2; while (true) { /* Let's offline if we hit buffer boundary (otherwise would * need to [try to] align input, which is bit complicated * and may not always be possible) */ if ((_inputEnd - _inputPtr) < 4) { return parseEscapedFieldName(_quadBuffer, qlen, 0, q, 0); } // Otherwise can skip boundary checks for 4 bytes in loop int i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { return findName(_quadBuffer, qlen, q, 1); } return parseEscapedFieldName(_quadBuffer, qlen, q, i, 1); } q = (q << 8) | i; i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { return findName(_quadBuffer, qlen, q, 2); } return parseEscapedFieldName(_quadBuffer, qlen, q, i, 2); } q = (q << 8) | i; i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { return findName(_quadBuffer, qlen, q, 3); } return parseEscapedFieldName(_quadBuffer, qlen, q, i, 3); } q = (q << 8) | i; i = _inputBuffer[_inputPtr++] & 0xFF; if (codes[i] != 0) { if (i == INT_QUOTE) { return findName(_quadBuffer, qlen, q, 4); } return parseEscapedFieldName(_quadBuffer, qlen, q, i, 4); } // Nope, no end in sight. Need to grow quad array etc if (qlen >= _quadBuffer.length) { _quadBuffer = growArrayBy(_quadBuffer, qlen); } _quadBuffer[qlen++] = q; q = i; } } /** * Method called when not even first 8 bytes are guaranteed * to come consequtively. Happens rarely, so this is offlined; * plus we'll also do full checks for escaping etc. */ protected Name slowParseFieldName() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(": was expecting closing '\"' for name"); } } int i = _inputBuffer[_inputPtr++] & 0xFF; if (i == INT_QUOTE) { // special case, "" return BytesToNameCanonicalizer.getEmptyName(); } return parseEscapedFieldName(_quadBuffer, 0, 0, i, 0); } private final Name parseFieldName(int q1, int ch, int lastQuadBytes) throws IOException, JsonParseException { return parseEscapedFieldName(_quadBuffer, 0, q1, ch, lastQuadBytes); } private final Name parseFieldName(int q1, int q2, int ch, int lastQuadBytes) throws IOException, JsonParseException { _quadBuffer[0] = q1; return parseEscapedFieldName(_quadBuffer, 1, q2, ch, lastQuadBytes); } /** * Slower parsing method which is generally branched to when * an escape sequence is detected (or alternatively for long * names, or ones crossing input buffer boundary). In any case, * needs to be able to handle more exceptional cases, gets * slower, and hance is offlined to a separate method. */ protected Name parseEscapedFieldName(int[] quads, int qlen, int currQuad, int ch, int currQuadBytes) throws IOException, JsonParseException { /* 25-Nov-2008, tatu: This may seem weird, but here we do * NOT want to worry about UTF-8 decoding. Rather, we'll * assume that part is ok (if not it will get caught * later on), and just handle quotes and backslashes here. */ final int[] codes = sInputCodesLatin1; while (true) { if (codes[ch] != 0) { if (ch == INT_QUOTE) { // we are done break; } // Unquoted white space? if (ch != INT_BACKSLASH) { // As per [JACKSON-208], call can now return: _throwUnquotedSpace(ch, "name"); } else { // Nope, escape sequence ch = _decodeEscaped(); } /* Oh crap. May need to UTF-8 (re-)encode it, if it's * beyond 7-bit ascii. Gets pretty messy. * If this happens often, may want to use different name * canonicalization to avoid these hits. */ if (ch > 127) { // Ok, we'll need room for first byte right away if (currQuadBytes >= 4) { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; currQuad = 0; currQuadBytes = 0; } if (ch < 0x800) { // 2-byte currQuad = (currQuad << 8) | (0xc0 | (ch >> 6)); ++currQuadBytes; // Second byte gets output below: } else { // 3 bytes; no need to worry about surrogates here currQuad = (currQuad << 8) | (0xe0 | (ch >> 12)); ++currQuadBytes; // need room for middle byte? if (currQuadBytes >= 4) { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; currQuad = 0; currQuadBytes = 0; } currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f)); ++currQuadBytes; } // And same last byte in both cases, gets output below: ch = 0x80 | (ch & 0x3f); } } // Ok, we have one more byte to add at any rate: if (currQuadBytes < 4) { ++currQuadBytes; currQuad = (currQuad << 8) | ch; } else { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; currQuad = ch; currQuadBytes = 1; } if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in field name"); } } ch = _inputBuffer[_inputPtr++] & 0xFF; } if (currQuadBytes > 0) { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; } Name name = _symbols.findName(quads, qlen); if (name == null) { name = addName(quads, qlen, currQuadBytes); } return name; } /** * Method called when we see non-white space character other * than double quote, when expecting a field name. * In standard mode will just throw an expection; but * in non-standard modes may be able to parse name. */ protected final Name _handleUnusualFieldName(int ch) throws IOException, JsonParseException { // [JACKSON-173]: allow single quotes if (ch == INT_APOSTROPHE && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { return _parseApostropheFieldName(); } // [JACKSON-69]: allow unquoted names if feature enabled: if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) { _reportUnexpectedChar(ch, "was expecting double-quote to start field name"); } /* Also: note that although we use a different table here, * it does NOT handle UTF-8 decoding. It'll just pass those * high-bit codes as acceptable for later decoding. */ final int[] codes = CharTypes.getInputCodeUtf8JsNames(); // Also: must start with a valid character... if (codes[ch] != 0) { _reportUnexpectedChar(ch, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name"); } /* Ok, now; instead of ultra-optimizing parsing here (as with * regular JSON names), let's just use the generic "slow" * variant. Can measure its impact later on if need be */ int[] quads = _quadBuffer; int qlen = 0; int currQuad = 0; int currQuadBytes = 0; while (true) { // Ok, we have one more byte to add at any rate: if (currQuadBytes < 4) { ++currQuadBytes; currQuad = (currQuad << 8) | ch; } else { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; currQuad = ch; currQuadBytes = 1; } if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in field name"); } } ch = _inputBuffer[_inputPtr] & 0xFF; if (codes[ch] != 0) { break; } ++_inputPtr; } if (currQuadBytes > 0) { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; } Name name = _symbols.findName(quads, qlen); if (name == null) { name = addName(quads, qlen, currQuadBytes); } return name; } /* Parsing to support [JACKSON-173]. Plenty of duplicated code; * main reason being to try to avoid slowing down fast path * for valid JSON -- more alternatives, more code, generally * bit slower execution. */ protected final Name _parseApostropheFieldName() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(": was expecting closing '\'' for name"); } } int ch = _inputBuffer[_inputPtr++] & 0xFF; if (ch == INT_APOSTROPHE) { // special case, '' return BytesToNameCanonicalizer.getEmptyName(); } int[] quads = _quadBuffer; int qlen = 0; int currQuad = 0; int currQuadBytes = 0; // Copied from parseEscapedFieldName, with minor mods: final int[] codes = sInputCodesLatin1; while (true) { if (ch == INT_APOSTROPHE) { break; } // additional check to skip handling of double-quotes if (ch != INT_QUOTE && codes[ch] != 0) { if (ch != INT_BACKSLASH) { // Unquoted white space? // As per [JACKSON-208], call can now return: _throwUnquotedSpace(ch, "name"); } else { // Nope, escape sequence ch = _decodeEscaped(); } /* Oh crap. May need to UTF-8 (re-)encode it, if it's * beyond 7-bit ascii. Gets pretty messy. * If this happens often, may want to use different name * canonicalization to avoid these hits. */ if (ch > 127) { // Ok, we'll need room for first byte right away if (currQuadBytes >= 4) { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; currQuad = 0; currQuadBytes = 0; } if (ch < 0x800) { // 2-byte currQuad = (currQuad << 8) | (0xc0 | (ch >> 6)); ++currQuadBytes; // Second byte gets output below: } else { // 3 bytes; no need to worry about surrogates here currQuad = (currQuad << 8) | (0xe0 | (ch >> 12)); ++currQuadBytes; // need room for middle byte? if (currQuadBytes >= 4) { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; currQuad = 0; currQuadBytes = 0; } currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f)); ++currQuadBytes; } // And same last byte in both cases, gets output below: ch = 0x80 | (ch & 0x3f); } } // Ok, we have one more byte to add at any rate: if (currQuadBytes < 4) { ++currQuadBytes; currQuad = (currQuad << 8) | ch; } else { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; currQuad = ch; currQuadBytes = 1; } if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in field name"); } } ch = _inputBuffer[_inputPtr++] & 0xFF; } if (currQuadBytes > 0) { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = currQuad; } Name name = _symbols.findName(quads, qlen); if (name == null) { name = addName(quads, qlen, currQuadBytes); } return name; } /* /********************************************************** /* Internal methods, symbol (name) handling /********************************************************** */ private final Name findName(int q1, int lastQuadBytes) throws JsonParseException { // Usually we'll find it from the canonical symbol table already Name name = _symbols.findName(q1); if (name != null) { return name; } // If not, more work. We'll need add stuff to buffer _quadBuffer[0] = q1; return addName(_quadBuffer, 1, lastQuadBytes); } private final Name findName(int q1, int q2, int lastQuadBytes) throws JsonParseException { // Usually we'll find it from the canonical symbol table already Name name = _symbols.findName(q1, q2); if (name != null) { return name; } // If not, more work. We'll need add stuff to buffer _quadBuffer[0] = q1; _quadBuffer[1] = q2; return addName(_quadBuffer, 2, lastQuadBytes); } private final Name findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException { if (qlen >= quads.length) { _quadBuffer = quads = growArrayBy(quads, quads.length); } quads[qlen++] = lastQuad; Name name = _symbols.findName(quads, qlen); if (name == null) { return addName(quads, qlen, lastQuadBytes); } return name; } /** * This is the main workhorse method used when we take a symbol * table miss. It needs to demultiplex individual bytes, decode * multi-byte chars (if any), and then construct Name instance * and add it to the symbol table. */ private final Name addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException { /* Ok: must decode UTF-8 chars. No other validation is * needed, since unescaping has been done earlier as necessary * (as well as error reporting for unescaped control chars) */ // 4 bytes per quad, except last one maybe less int byteLen = (qlen << 2) - 4 + lastQuadBytes; /* And last one is not correctly aligned (leading zero bytes instead * need to shift a bit, instead of trailing). Only need to shift it * for UTF-8 decoding; need revert for storage (since key will not * be aligned, to optimize lookup speed) */ int lastQuad; if (lastQuadBytes < 4) { lastQuad = quads[qlen-1]; // 8/16/24 bit left shift quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3)); } else { lastQuad = 0; } // Need some working space, TextBuffer works well: char[] cbuf = _textBuffer.emptyAndGetCurrentSegment(); int cix = 0; for (int ix = 0; ix < byteLen; ) { int ch = quads[ix >> 2]; // current quad, need to shift+mask int byteIx = (ix & 3); ch = (ch >> ((3 - byteIx) << 3)) & 0xFF; ++ix; if (ch > 127) { // multi-byte int needed; if ((ch & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) ch &= 0x1F; needed = 1; } else if ((ch & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) ch &= 0x0F; needed = 2; } else if ((ch & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all... ch &= 0x07; needed = 3; } else { // 5- and 6-byte chars not valid xml chars _reportInvalidInitial(ch); needed = ch = 1; // never really gets this far } if ((ix + needed) > byteLen) { _reportInvalidEOF(" in field name"); } // Ok, always need at least one more: int ch2 = quads[ix >> 2]; // current quad, need to shift+mask byteIx = (ix & 3); ch2 = (ch2 >> ((3 - byteIx) << 3)); ++ix; if ((ch2 & 0xC0) != 0x080) { _reportInvalidOther(ch2); } ch = (ch << 6) | (ch2 & 0x3F); if (needed > 1) { ch2 = quads[ix >> 2]; byteIx = (ix & 3); ch2 = (ch2 >> ((3 - byteIx) << 3)); ++ix; if ((ch2 & 0xC0) != 0x080) { _reportInvalidOther(ch2); } ch = (ch << 6) | (ch2 & 0x3F); if (needed > 2) { // 4 bytes? (need surrogates on output) ch2 = quads[ix >> 2]; byteIx = (ix & 3); ch2 = (ch2 >> ((3 - byteIx) << 3)); ++ix; if ((ch2 & 0xC0) != 0x080) { _reportInvalidOther(ch2 & 0xFF); } ch = (ch << 6) | (ch2 & 0x3F); } } if (needed > 2) { // surrogate pair? once again, let's output one here, one later on ch -= 0x10000; // to normalize it starting with 0x0 if (cix >= cbuf.length) { cbuf = _textBuffer.expandCurrentSegment(); } cbuf[cix++] = (char) (0xD800 + (ch >> 10)); ch = 0xDC00 | (ch & 0x03FF); } } if (cix >= cbuf.length) { cbuf = _textBuffer.expandCurrentSegment(); } cbuf[cix++] = (char) ch; } // Ok. Now we have the character array, and can construct the String String baseName = new String(cbuf, 0, cix); // And finally, un-align if necessary if (lastQuadBytes < 4) { quads[qlen-1] = lastQuad; } return _symbols.addName(baseName, quads, qlen); } /* /********************************************************** /* Internal methods, String value parsing /********************************************************** */ @Override protected void _finishString() throws IOException, JsonParseException { // First, single tight loop for ASCII content, not split across input buffer boundary: int ptr = _inputPtr; if (ptr >= _inputEnd) { loadMoreGuaranteed(); ptr = _inputPtr; } int outPtr = 0; char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); final int[] codes = sInputCodesUtf8; final int max = Math.min(_inputEnd, (ptr + outBuf.length)); final byte[] inputBuffer = _inputBuffer; while (ptr < max) { int c = (int) inputBuffer[ptr] & 0xFF; if (codes[c] != 0) { if (c == INT_QUOTE) { _inputPtr = ptr+1; _textBuffer.setCurrentLength(outPtr); return; } break; } ++ptr; outBuf[outPtr++] = (char) c; } _inputPtr = ptr; _finishString2(outBuf, outPtr); } private final void _finishString2(char[] outBuf, int outPtr) throws IOException, JsonParseException { int c; // Here we do want to do full decoding, hence: final int[] codes = sInputCodesUtf8; final byte[] inputBuffer = _inputBuffer; main_loop: while (true) { // Then the tight ASCII non-funny-char loop: ascii_loop: while (true) { int ptr = _inputPtr; if (ptr >= _inputEnd) { loadMoreGuaranteed(); ptr = _inputPtr; } if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr))); while (ptr < max) { c = (int) inputBuffer[ptr++] & 0xFF; if (codes[c] != 0) { _inputPtr = ptr; break ascii_loop; } outBuf[outPtr++] = (char) c; } _inputPtr = ptr; } // Ok: end marker, escape or multi-byte? if (c == INT_QUOTE) { break main_loop; } switch (codes[c]) { case 1: // backslash c = _decodeEscaped(); break; case 2: // 2-byte UTF c = _decodeUtf8_2(c); break; case 3: // 3-byte UTF if ((_inputEnd - _inputPtr) >= 2) { c = _decodeUtf8_3fast(c); } else { c = _decodeUtf8_3(c); } break; case 4: // 4-byte UTF c = _decodeUtf8_4(c); // Let's add first part right away: outBuf[outPtr++] = (char) (0xD800 | (c >> 10)); if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } c = 0xDC00 | (c & 0x3FF); // And let the other char output down below break; default: if (c < INT_SPACE) { // As per [JACKSON-208], call can now return: _throwUnquotedSpace(c, "string value"); } else { // Is this good enough error message? _reportInvalidChar(c); } } // Need more room? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } // Ok, let's add char to output: outBuf[outPtr++] = (char) c; } _textBuffer.setCurrentLength(outPtr); } /** * Method called to skim through rest of unparsed String value, * if it is not needed. This can be done bit faster if contents * need not be stored for future access. */ protected void _skipString() throws IOException, JsonParseException { _tokenIncomplete = false; // Need to be fully UTF-8 aware here: final int[] codes = sInputCodesUtf8; final byte[] inputBuffer = _inputBuffer; main_loop: while (true) { int c; ascii_loop: while (true) { int ptr = _inputPtr; int max = _inputEnd; if (ptr >= max) { loadMoreGuaranteed(); ptr = _inputPtr; max = _inputEnd; } while (ptr < max) { c = (int) inputBuffer[ptr++] & 0xFF; if (codes[c] != 0) { _inputPtr = ptr; break ascii_loop; } } _inputPtr = ptr; } // Ok: end marker, escape or multi-byte? if (c == INT_QUOTE) { break main_loop; } switch (codes[c]) { case 1: // backslash _decodeEscaped(); break; case 2: // 2-byte UTF _skipUtf8_2(c); break; case 3: // 3-byte UTF _skipUtf8_3(c); break; case 4: // 4-byte UTF _skipUtf8_4(c); break; default: if (c < INT_SPACE) { // As per [JACKSON-208], call can now return: _throwUnquotedSpace(c, "string value"); } else { // Is this good enough error message? _reportInvalidChar(c); } } } } /** * Method for handling cases where first non-space character * of an expected value token is not legal for standard JSON content. * * @since 1.3 */ protected JsonToken _handleUnexpectedValue(int c) throws IOException, JsonParseException { // Most likely an error, unless we are to allow single-quote-strings switch (c) { case '\'': if (isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { return _handleApostropheValue(); } break; case 'N': _matchToken("NaN", 1); if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { return resetAsNaN("NaN", Double.NaN); } _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow"); break; case '+': // note: '-' is taken as number if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOFInValue(); } } return _handleInvalidNumberStart(_inputBuffer[_inputPtr++] & 0xFF, false); } _reportUnexpectedChar(c, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')"); return null; } protected JsonToken _handleApostropheValue() throws IOException, JsonParseException { int c = 0; // Otherwise almost verbatim copy of _finishString() int outPtr = 0; char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); // Here we do want to do full decoding, hence: final int[] codes = sInputCodesUtf8; final byte[] inputBuffer = _inputBuffer; main_loop: while (true) { // Then the tight ascii non-funny-char loop: ascii_loop: while (true) { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } int max = _inputEnd; { int max2 = _inputPtr + (outBuf.length - outPtr); if (max2 < max) { max = max2; } } while (_inputPtr < max) { c = (int) inputBuffer[_inputPtr++] & 0xFF; if (c == INT_APOSTROPHE || codes[c] != 0) { break ascii_loop; } outBuf[outPtr++] = (char) c; } } // Ok: end marker, escape or multi-byte? if (c == INT_APOSTROPHE) { break main_loop; } switch (codes[c]) { case 1: // backslash if (c != INT_QUOTE) { // marked as special, isn't here c = _decodeEscaped(); } break; case 2: // 2-byte UTF c = _decodeUtf8_2(c); break; case 3: // 3-byte UTF if ((_inputEnd - _inputPtr) >= 2) { c = _decodeUtf8_3fast(c); } else { c = _decodeUtf8_3(c); } break; case 4: // 4-byte UTF c = _decodeUtf8_4(c); // Let's add first part right away: outBuf[outPtr++] = (char) (0xD800 | (c >> 10)); if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } c = 0xDC00 | (c & 0x3FF); // And let the other char output down below break; default: if (c < INT_SPACE) { _throwUnquotedSpace(c, "string value"); } // Is this good enough error message? _reportInvalidChar(c); } // Need more room? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } // Ok, let's add char to output: outBuf[outPtr++] = (char) c; } _textBuffer.setCurrentLength(outPtr); return JsonToken.VALUE_STRING; } /** * Method called if expected numeric value (due to leading sign) does not * look like a number */ protected JsonToken _handleInvalidNumberStart(int ch, boolean negative) throws IOException, JsonParseException { if (ch == 'I') { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOFInValue(); } } ch = _inputBuffer[_inputPtr++]; if (ch == 'N') { String match = negative ? "-INF" :"+INF"; _matchToken(match, 3); if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY); } _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow"); } else if (ch == 'n') { String match = negative ? "-Infinity" :"+Infinity"; _matchToken(match, 3); if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY); } _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow"); } } reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value"); return null; } protected final void _matchToken(String matchStr, int i) throws IOException, JsonParseException { final int len = matchStr.length(); do { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in a value"); } } if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) { _reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN"); } ++_inputPtr; } while (++i < len); // but let's also ensure we either get EOF, or non-alphanum char... if (_inputPtr >= _inputEnd) { if (!loadMore()) { return; } } int ch = _inputBuffer[_inputPtr] & 0xFF; if (ch < '0' || ch == ']' || ch == '}') { // expected/allowed chars return; } // but actually only alphanums are problematic char c = (char) _decodeCharForError(ch); if (Character.isJavaIdentifierPart(c)) { ++_inputPtr; _reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN"); } } protected void _reportInvalidToken(String matchedPart, String msg) throws IOException, JsonParseException { StringBuilder sb = new StringBuilder(matchedPart); /* Let's just try to find what appears to be the token, using * regular Java identifier character rules. It's just a heuristic, * nothing fancy here (nor fast). */ while (true) { if (_inputPtr >= _inputEnd && !loadMore()) { break; } int i = (int) _inputBuffer[_inputPtr++]; char c = (char) _decodeCharForError(i); if (!Character.isJavaIdentifierPart(c)) { break; } ++_inputPtr; sb.append(c); } _reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg); } /* /********************************************************** /* Internal methods, ws skipping, escape/unescape /********************************************************** */ private final int _skipWS() throws IOException, JsonParseException { while (_inputPtr < _inputEnd || loadMore()) { int i = _inputBuffer[_inputPtr++] & 0xFF; if (i > INT_SPACE) { if (i != INT_SLASH) { return i; } _skipComment(); } else if (i != INT_SPACE) { if (i == INT_LF) { _skipLF(); } else if (i == INT_CR) { _skipCR(); } else if (i != INT_TAB) { _throwInvalidSpace(i); } } } throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries"); } private final int _skipWSOrEnd() throws IOException, JsonParseException { while ((_inputPtr < _inputEnd) || loadMore()) { int i = _inputBuffer[_inputPtr++] & 0xFF; if (i > INT_SPACE) { if (i != INT_SLASH) { return i; } _skipComment(); } else if (i != INT_SPACE) { if (i == INT_LF) { _skipLF(); } else if (i == INT_CR) { _skipCR(); } else if (i != INT_TAB) { _throwInvalidSpace(i); } } } // We ran out of input... _handleEOF(); return -1; } /** * Helper method for matching and skipping a colon character, * optionally surrounded by white space * * @since 1.9 */ private final int _skipColon() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } // first fast case: we just got a colon without white space: int i = _inputBuffer[_inputPtr++]; if (i == INT_COLON) { if (_inputPtr < _inputEnd) { i = _inputBuffer[_inputPtr] & 0xFF; if (i > INT_SPACE && i != INT_SLASH) { ++_inputPtr; return i; } } } else { // need to skip potential leading space i &= 0xFF; space_loop: while (true) { switch (i) { case INT_SPACE: case INT_TAB: case INT_CR: _skipCR(); break; case INT_LF: _skipLF(); break; case INT_SLASH: _skipComment(); break; default: if (i < INT_SPACE) { _throwInvalidSpace(i); } break space_loop; } } if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } i = _inputBuffer[_inputPtr++] & 0xFF; if (i != INT_COLON) { _reportUnexpectedChar(i, "was expecting a colon to separate field name and value"); } } // either way, found colon, skip through trailing WS while (_inputPtr < _inputEnd || loadMore()) { i = _inputBuffer[_inputPtr++] & 0xFF; if (i > INT_SPACE) { if (i != INT_SLASH) { return i; } _skipComment(); } else if (i != INT_SPACE) { if (i == INT_LF) { _skipLF(); } else if (i == INT_CR) { _skipCR(); } else if (i != INT_TAB) { _throwInvalidSpace(i); } } } throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries"); } private final void _skipComment() throws IOException, JsonParseException { if (!isEnabled(Feature.ALLOW_COMMENTS)) { _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)"); } // First: check which comment (if either) it is: if (_inputPtr >= _inputEnd && !loadMore()) { _reportInvalidEOF(" in a comment"); } int c = _inputBuffer[_inputPtr++] & 0xFF; if (c == INT_SLASH) { _skipCppComment(); } else if (c == INT_ASTERISK) { _skipCComment(); } else { _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment"); } } private final void _skipCComment() throws IOException, JsonParseException { // Need to be UTF-8 aware here to decode content (for skipping) final int[] codes = CharTypes.getInputCodeComment(); // Ok: need the matching '*/' while ((_inputPtr < _inputEnd) || loadMore()) { int i = (int) _inputBuffer[_inputPtr++] & 0xFF; int code = codes[i]; if (code != 0) { switch (code) { case INT_ASTERISK: if (_inputBuffer[_inputPtr] == INT_SLASH) { ++_inputPtr; return; } break; case INT_LF: _skipLF(); break; case INT_CR: _skipCR(); break; default: // e.g. -1 // Is this good enough error message? _reportInvalidChar(i); } } } _reportInvalidEOF(" in a comment"); } private final void _skipCppComment() throws IOException, JsonParseException { // Ok: need to find EOF or linefeed final int[] codes = CharTypes.getInputCodeComment(); while ((_inputPtr < _inputEnd) || loadMore()) { int i = (int) _inputBuffer[_inputPtr++] & 0xFF; int code = codes[i]; if (code != 0) { switch (code) { case INT_LF: _skipLF(); return; case INT_CR: _skipCR(); return; case INT_ASTERISK: // nop for these comments break; default: // e.g. -1 // Is this good enough error message? _reportInvalidChar(i); } } } } @Override protected final char _decodeEscaped() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in character escape sequence"); } } int c = (int) _inputBuffer[_inputPtr++]; switch ((int) c) { // First, ones that are mapped case INT_b: return '\b'; case INT_t: return '\t'; case INT_n: return '\n'; case INT_f: return '\f'; case INT_r: return '\r'; // And these are to be returned as they are case INT_QUOTE: case INT_SLASH: case INT_BACKSLASH: return (char) c; case INT_u: // and finally hex-escaped break; default: return _handleUnrecognizedCharacterEscape((char) _decodeCharForError(c)); } // Ok, a hex escape. Need 4 characters int value = 0; for (int i = 0; i < 4; ++i) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in character escape sequence"); } } int ch = (int) _inputBuffer[_inputPtr++]; int digit = CharTypes.charToHex(ch); if (digit < 0) { _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence"); } value = (value << 4) | digit; } return (char) value; } protected int _decodeCharForError(int firstByte) throws IOException, JsonParseException { int c = (int) firstByte; if (c < 0) { // if >= 0, is ascii and fine as is int needed; // Ok; if we end here, we got multi-byte combination if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) c &= 0x1F; needed = 1; } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) c &= 0x0F; needed = 2; } else if ((c & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all... c &= 0x07; needed = 3; } else { _reportInvalidInitial(c & 0xFF); needed = 1; // never gets here } int d = nextByte(); if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF); } c = (c << 6) | (d & 0x3F); if (needed > 1) { // needed == 1 means 2 bytes total d = nextByte(); // 3rd byte if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF); } c = (c << 6) | (d & 0x3F); if (needed > 2) { // 4 bytes? (need surrogates) d = nextByte(); if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF); } c = (c << 6) | (d & 0x3F); } } } return c; } /* /********************************************************** /* Internal methods,UTF8 decoding /********************************************************** */ private final int _decodeUtf8_2(int c) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } return ((c & 0x1F) << 6) | (d & 0x3F); } private final int _decodeUtf8_3(int c1) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } c1 &= 0x0F; int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } int c = (c1 << 6) | (d & 0x3F); if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = (c << 6) | (d & 0x3F); return c; } private final int _decodeUtf8_3fast(int c1) throws IOException, JsonParseException { c1 &= 0x0F; int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } int c = (c1 << 6) | (d & 0x3F); d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = (c << 6) | (d & 0x3F); return c; } /** * @return Character value minus 0x10000; this so that caller * can readily expand it to actual surrogates */ private final int _decodeUtf8_4(int c) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = ((c & 0x07) << 6) | (d & 0x3F); if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } c = (c << 6) | (d & 0x3F); if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } /* note: won't change it to negative here, since caller * already knows it'll need a surrogate */ return ((c << 6) | (d & 0x3F)) - 0x10000; } private final void _skipUtf8_2(int c) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } c = (int) _inputBuffer[_inputPtr++]; if ((c & 0xC0) != 0x080) { _reportInvalidOther(c & 0xFF, _inputPtr); } } /* Alas, can't heavily optimize skipping, since we still have to * do validity checks... */ private final void _skipUtf8_3(int c) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } //c &= 0x0F; c = (int) _inputBuffer[_inputPtr++]; if ((c & 0xC0) != 0x080) { _reportInvalidOther(c & 0xFF, _inputPtr); } if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } c = (int) _inputBuffer[_inputPtr++]; if ((c & 0xC0) != 0x080) { _reportInvalidOther(c & 0xFF, _inputPtr); } } private final void _skipUtf8_4(int c) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } int d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } d = (int) _inputBuffer[_inputPtr++]; if ((d & 0xC0) != 0x080) { _reportInvalidOther(d & 0xFF, _inputPtr); } } /* /********************************************************** /* Internal methods, input loading /********************************************************** */ /** * We actually need to check the character value here * (to see if we have \n following \r). */ protected final void _skipCR() throws IOException { if (_inputPtr < _inputEnd || loadMore()) { if (_inputBuffer[_inputPtr] == BYTE_LF) { ++_inputPtr; } } ++_currInputRow; _currInputRowStart = _inputPtr; } protected final void _skipLF() throws IOException { ++_currInputRow; _currInputRowStart = _inputPtr; } private int nextByte() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } return _inputBuffer[_inputPtr++] & 0xFF; } /* /********************************************************** /* Internal methods, error reporting /********************************************************** */ protected void _reportInvalidChar(int c) throws JsonParseException { // Either invalid WS or illegal UTF-8 start char if (c < INT_SPACE) { _throwInvalidSpace(c); } _reportInvalidInitial(c); } protected void _reportInvalidInitial(int mask) throws JsonParseException { _reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask)); } protected void _reportInvalidOther(int mask) throws JsonParseException { _reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask)); } protected void _reportInvalidOther(int mask, int ptr) throws JsonParseException { _inputPtr = ptr; _reportInvalidOther(mask); } public static int[] growArrayBy(int[] arr, int more) { if (arr == null) { return new int[more]; } int[] old = arr; int len = arr.length; arr = new int[len + more]; System.arraycopy(old, 0, arr, 0, len); return arr; } /* /********************************************************** /* Binary access /********************************************************** */ @Override protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException, JsonParseException { ByteArrayBuilder builder = _getByteArrayBuilder(); //main_loop: while (true) { // first, we'll skip preceding white space, if any int ch; do { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = (int) _inputBuffer[_inputPtr++] & 0xFF; } while (ch <= INT_SPACE); int bits = b64variant.decodeBase64Char(ch); if (bits < 0) { // reached the end, fair and square? if (ch == INT_QUOTE) { return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 0); if (bits < 0) { // white space to skip continue; } } int decodedData = bits; // then second base64 char; can't get padding yet, nor ws if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++] & 0xFF; bits = b64variant.decodeBase64Char(ch); if (bits < 0) { bits = _decodeBase64Escape(b64variant, ch, 1); } decodedData = (decodedData << 6) | bits; // third base64 char; can be padding, but not ws if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++] & 0xFF; bits = b64variant.decodeBase64Char(ch); // First branch: can get padding (-> 1 byte) if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { // as per [JACKSON-631], could also just be 'missing' padding if (ch == '"' && !b64variant.usesPadding()) { decodedData >>= 4; builder.append(decodedData); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 2); } if (bits == Base64Variant.BASE64_VALUE_PADDING) { // Ok, must get padding if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++] & 0xFF; if (!b64variant.usesPaddingChar(ch)) { throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'"); } // Got 12 bits, only need 8, need to shift decodedData >>= 4; builder.append(decodedData); continue; } } // Nope, 2 or 3 bytes decodedData = (decodedData << 6) | bits; // fourth and last base64 char; can be padding, but not ws if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++] & 0xFF; bits = b64variant.decodeBase64Char(ch); if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { // as per [JACKSON-631], could also just be 'missing' padding if (ch == '"' && !b64variant.usesPadding()) { decodedData >>= 2; builder.appendTwoBytes(decodedData); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 3); } if (bits == Base64Variant.BASE64_VALUE_PADDING) { /* With padding we only get 2 bytes; but we have * to shift it a bit so it is identical to triplet * case with partial output. * 3 chars gives 3x6 == 18 bits, of which 2 are * dummies, need to discard: */ decodedData >>= 2; builder.appendTwoBytes(decodedData); continue; } } // otherwise, our triplet is now complete decodedData = (decodedData << 6) | bits; builder.appendThreeBytes(decodedData); } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/DefaultPrettyPrinter.java0000644000175000017500000000050211655120726030102 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; /** * Deprecated version of the default pretty printer. * * @deprecated Moved to {@link org.codehaus.jackson.util.DefaultPrettyPrinter}; will be removed in Jackson 2.0 */ @Deprecated public class DefaultPrettyPrinter extends org.codehaus.jackson.util.DefaultPrettyPrinter { } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/Indenter.java0000644000175000017500000000117211655120726025516 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.IOException; import org.codehaus.jackson.*; /** * Interface that defines objects that can produce indentation used * to separate object entries and array values. Indentation in this * context just means insertion of white space, independent of whether * linefeeds are output. */ public interface Indenter { public void writeIndentation(JsonGenerator jg, int level) throws IOException, JsonGenerationException; /** * @return True if indenter is considered inline (does not add linefeeds), * false otherwise */ public boolean isInline(); } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/JsonNumericParserBase.java0000644000175000017500000000112011655120726030143 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import org.codehaus.jackson.*; import org.codehaus.jackson.io.IOContext; /** * Another intermediate base class used by all Jackson {@link JsonParser} * implementations. Contains shared functionality for dealing with * number parsing aspects, independent of input source decoding. * * @deprecated Since 1.9.0: functionality demoted down to JsonParserBase */ @Deprecated public abstract class JsonNumericParserBase extends JsonParserBase { protected JsonNumericParserBase(IOContext ctxt, int features) { super(ctxt, features); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/JsonParserMinimalBase.java0000644000175000017500000003021011655120726030131 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.JsonParser.Feature; import org.codehaus.jackson.io.NumberInput; /** * Intermediate base class used by all Jackson {@link JsonParser} * implementations, but does not add any additional fields that depend * on particular method of obtaining input. * * @since 1.6 * * @author Tatu Saloranta */ public abstract class JsonParserMinimalBase extends JsonParser { // Control chars: protected final static int INT_TAB = '\t'; protected final static int INT_LF = '\n'; protected final static int INT_CR = '\r'; protected final static int INT_SPACE = 0x0020; // Markup protected final static int INT_LBRACKET = '['; protected final static int INT_RBRACKET = ']'; protected final static int INT_LCURLY = '{'; protected final static int INT_RCURLY = '}'; protected final static int INT_QUOTE = '"'; protected final static int INT_BACKSLASH = '\\'; protected final static int INT_SLASH = '/'; protected final static int INT_COLON = ':'; protected final static int INT_COMMA = ','; protected final static int INT_ASTERISK = '*'; protected final static int INT_APOSTROPHE = '\''; // Letters we need protected final static int INT_b = 'b'; protected final static int INT_f = 'f'; protected final static int INT_n = 'n'; protected final static int INT_r = 'r'; protected final static int INT_t = 't'; protected final static int INT_u = 'u'; /* /********************************************************** /* Life-cycle /********************************************************** */ protected JsonParserMinimalBase() { } protected JsonParserMinimalBase(int features) { super(features); } /* /********************************************************** /* Configuration overrides if any /********************************************************** */ // from base class: //public void enableFeature(Feature f) //public void disableFeature(Feature f) //public void setFeature(Feature f, boolean state) //public boolean isFeatureEnabled(Feature f) /* /********************************************************** /* JsonParser impl /********************************************************** */ @Override public abstract JsonToken nextToken() throws IOException, JsonParseException; //public final JsonToken nextValue() @Override public JsonParser skipChildren() throws IOException, JsonParseException { if (_currToken != JsonToken.START_OBJECT && _currToken != JsonToken.START_ARRAY) { return this; } int open = 1; /* Since proper matching of start/end markers is handled * by nextToken(), we'll just count nesting levels here */ while (true) { JsonToken t = nextToken(); if (t == null) { _handleEOF(); /* given constraints, above should never return; * however, FindBugs doesn't know about it and * complains... so let's add dummy break here */ return this; } switch (t) { case START_OBJECT: case START_ARRAY: ++open; break; case END_OBJECT: case END_ARRAY: if (--open == 0) { return this; } break; } } } /** * Method sub-classes need to implement */ protected abstract void _handleEOF() throws JsonParseException; //public JsonToken getCurrentToken() //public boolean hasCurrentToken() @Override public abstract String getCurrentName() throws IOException, JsonParseException; @Override public abstract void close() throws IOException; @Override public abstract boolean isClosed(); @Override public abstract JsonStreamContext getParsingContext(); // public abstract JsonLocation getTokenLocation(); // public abstract JsonLocation getCurrentLocation(); /* /********************************************************** /* Public API, access to token information, text /********************************************************** */ @Override public abstract String getText() throws IOException, JsonParseException; @Override public abstract char[] getTextCharacters() throws IOException, JsonParseException; @Override public abstract boolean hasTextCharacters(); @Override public abstract int getTextLength() throws IOException, JsonParseException; @Override public abstract int getTextOffset() throws IOException, JsonParseException; /* /********************************************************** /* Public API, access to token information, binary /********************************************************** */ @Override public abstract byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException; /* /********************************************************** /* Public API, access with conversion/coercion /********************************************************** */ @Override public boolean getValueAsBoolean(boolean defaultValue) throws IOException, JsonParseException { if (_currToken != null) { switch (_currToken) { case VALUE_NUMBER_INT: return getIntValue() != 0; case VALUE_TRUE: return true; case VALUE_FALSE: case VALUE_NULL: return false; case VALUE_EMBEDDED_OBJECT: { Object value = this.getEmbeddedObject(); if (value instanceof Boolean) { return ((Boolean) value).booleanValue(); } } case VALUE_STRING: String str = getText().trim(); if ("true".equals(str)) { return true; } break; } } return defaultValue; } @Override public int getValueAsInt(int defaultValue) throws IOException, JsonParseException { if (_currToken != null) { switch (_currToken) { case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return getIntValue(); case VALUE_TRUE: return 1; case VALUE_FALSE: case VALUE_NULL: return 0; case VALUE_STRING: return NumberInput.parseAsInt(getText(), defaultValue); case VALUE_EMBEDDED_OBJECT: { Object value = this.getEmbeddedObject(); if (value instanceof Number) { return ((Number) value).intValue(); } } } } return defaultValue; } @Override public long getValueAsLong(long defaultValue) throws IOException, JsonParseException { if (_currToken != null) { switch (_currToken) { case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return getLongValue(); case VALUE_TRUE: return 1; case VALUE_FALSE: case VALUE_NULL: return 0; case VALUE_STRING: return NumberInput.parseAsLong(getText(), defaultValue); case VALUE_EMBEDDED_OBJECT: { Object value = this.getEmbeddedObject(); if (value instanceof Number) { return ((Number) value).longValue(); } } } } return defaultValue; } @Override public double getValueAsDouble(double defaultValue) throws IOException, JsonParseException { if (_currToken != null) { switch (_currToken) { case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return getDoubleValue(); case VALUE_TRUE: return 1; case VALUE_FALSE: case VALUE_NULL: return 0; case VALUE_STRING: return NumberInput.parseAsDouble(getText(), defaultValue); case VALUE_EMBEDDED_OBJECT: { Object value = this.getEmbeddedObject(); if (value instanceof Number) { return ((Number) value).doubleValue(); } } } } return defaultValue; } /* /********************************************************** /* Error reporting /********************************************************** */ protected void _reportUnexpectedChar(int ch, String comment) throws JsonParseException { String msg = "Unexpected character ("+_getCharDesc(ch)+")"; if (comment != null) { msg += ": "+comment; } _reportError(msg); } protected void _reportInvalidEOF() throws JsonParseException { _reportInvalidEOF(" in "+_currToken); } protected void _reportInvalidEOF(String msg) throws JsonParseException { _reportError("Unexpected end-of-input"+msg); } protected void _reportInvalidEOFInValue() throws JsonParseException { _reportInvalidEOF(" in a value"); } protected void _throwInvalidSpace(int i) throws JsonParseException { char c = (char) i; String msg = "Illegal character ("+_getCharDesc(c)+"): only regular white space (\\r, \\n, \\t) is allowed between tokens"; _reportError(msg); } /** * Method called to report a problem with unquoted control character. * Note: starting with version 1.4, it is possible to suppress * exception by enabling {@link Feature#ALLOW_UNQUOTED_CONTROL_CHARS}. */ protected void _throwUnquotedSpace(int i, String ctxtDesc) throws JsonParseException { // JACKSON-208; possible to allow unquoted control chars: if (!isEnabled(Feature.ALLOW_UNQUOTED_CONTROL_CHARS) || i >= INT_SPACE) { char c = (char) i; String msg = "Illegal unquoted character ("+_getCharDesc(c)+"): has to be escaped using backslash to be included in "+ctxtDesc; _reportError(msg); } } protected char _handleUnrecognizedCharacterEscape(char ch) throws JsonProcessingException { // as per [JACKSON-300] if (isEnabled(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)) { return ch; } // and [JACKSON-548] if (ch == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { return ch; } _reportError("Unrecognized character escape "+_getCharDesc(ch)); return ch; } /* /********************************************************** /* Error reporting, generic /********************************************************** */ protected final static String _getCharDesc(int ch) { char c = (char) ch; if (Character.isISOControl(c)) { return "(CTRL-CHAR, code "+ch+")"; } if (ch > 255) { return "'"+c+"' (code "+ch+" / 0x"+Integer.toHexString(ch)+")"; } return "'"+c+"' (code "+ch+")"; } protected final void _reportError(String msg) throws JsonParseException { throw _constructError(msg); } protected final void _wrapError(String msg, Throwable t) throws JsonParseException { throw _constructError(msg, t); } protected final void _throwInternal() { throw new RuntimeException("Internal error: this code path should never get executed"); } protected final JsonParseException _constructError(String msg, Throwable t) { return new JsonParseException(msg, getCurrentLocation(), t); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/ByteSourceBootstrapper.java0000644000175000017500000004204311655120726030441 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.format.InputAccessor; import org.codehaus.jackson.format.MatchStrength; import org.codehaus.jackson.io.*; import org.codehaus.jackson.sym.BytesToNameCanonicalizer; import org.codehaus.jackson.sym.CharsToNameCanonicalizer; /** * This class is used to determine the encoding of byte stream * that is to contain JSON content. Rules are fairly simple, and * defined in JSON specification (RFC-4627 or newer), except * for BOM handling, which is a property of underlying * streams. */ public final class ByteSourceBootstrapper { final static byte UTF8_BOM_1 = (byte) 0xEF; final static byte UTF8_BOM_2 = (byte) 0xBB; final static byte UTF8_BOM_3 = (byte) 0xBF; /* /********************************************************** /* Configuration /********************************************************** */ protected final IOContext _context; protected final InputStream _in; /* /********************************************************** /* Input buffering /********************************************************** */ protected final byte[] _inputBuffer; private int _inputPtr; private int _inputEnd; /** * Flag that indicates whether buffer above is to be recycled * after being used or not. */ private final boolean _bufferRecyclable; /* /********************************************************** /* Input location /********************************************************** */ /** * Current number of input units (bytes or chars) that were processed in * previous blocks, * before contents of current input buffer. *

* Note: includes possible BOMs, if those were part of the input. */ protected int _inputProcessed; /* /********************************************************** /* Data gathered /********************************************************** */ protected boolean _bigEndian = true; protected int _bytesPerChar = 0; // 0 means "dunno yet" /* /********************************************************** /* Life-cycle /********************************************************** */ public ByteSourceBootstrapper(IOContext ctxt, InputStream in) { _context = ctxt; _in = in; _inputBuffer = ctxt.allocReadIOBuffer(); _inputEnd = _inputPtr = 0; _inputProcessed = 0; _bufferRecyclable = true; } public ByteSourceBootstrapper(IOContext ctxt, byte[] inputBuffer, int inputStart, int inputLen) { _context = ctxt; _in = null; _inputBuffer = inputBuffer; _inputPtr = inputStart; _inputEnd = (inputStart + inputLen); // Need to offset this for correct location info _inputProcessed = -inputStart; _bufferRecyclable = false; } /* /********************************************************** /* Encoding detection during bootstrapping /********************************************************** */ /** * Method that should be called after constructing an instace. * It will figure out encoding that content uses, to allow * for instantiating a proper scanner object. */ public JsonEncoding detectEncoding() throws IOException, JsonParseException { boolean foundEncoding = false; // First things first: BOM handling /* Note: we can require 4 bytes to be read, since no * combination of BOM + valid JSON content can have * shorter length (shortest valid JSON content is single * digit char, but BOMs are chosen such that combination * is always at least 4 chars long) */ if (ensureLoaded(4)) { int quad = (_inputBuffer[_inputPtr] << 24) | ((_inputBuffer[_inputPtr+1] & 0xFF) << 16) | ((_inputBuffer[_inputPtr+2] & 0xFF) << 8) | (_inputBuffer[_inputPtr+3] & 0xFF); if (handleBOM(quad)) { foundEncoding = true; } else { /* If no BOM, need to auto-detect based on first char; * this works since it must be 7-bit ascii (wrt. unicode * compatible encodings, only ones JSON can be transferred * over) */ // UTF-32? if (checkUTF32(quad)) { foundEncoding = true; } else if (checkUTF16(quad >>> 16)) { foundEncoding = true; } } } else if (ensureLoaded(2)) { int i16 = ((_inputBuffer[_inputPtr] & 0xFF) << 8) | (_inputBuffer[_inputPtr+1] & 0xFF); if (checkUTF16(i16)) { foundEncoding = true; } } JsonEncoding enc; /* Not found yet? As per specs, this means it must be UTF-8. */ if (!foundEncoding) { enc = JsonEncoding.UTF8; } else { switch (_bytesPerChar) { case 1: enc = JsonEncoding.UTF8; break; case 2: enc = _bigEndian ? JsonEncoding.UTF16_BE : JsonEncoding.UTF16_LE; break; case 4: enc = _bigEndian ? JsonEncoding.UTF32_BE : JsonEncoding.UTF32_LE; break; default: throw new RuntimeException("Internal error"); // should never get here } } _context.setEncoding(enc); return enc; } /* /********************************************************** /* Constructing a Reader /********************************************************** */ public Reader constructReader() throws IOException { JsonEncoding enc = _context.getEncoding(); switch (enc) { case UTF32_BE: case UTF32_LE: return new UTF32Reader(_context, _in, _inputBuffer, _inputPtr, _inputEnd, _context.getEncoding().isBigEndian()); case UTF16_BE: case UTF16_LE: case UTF8: // only in non-common case where we don't want to do direct mapping { // First: do we have a Stream? If not, need to create one: InputStream in = _in; if (in == null) { in = new ByteArrayInputStream(_inputBuffer, _inputPtr, _inputEnd); } else { /* Also, if we have any read but unused input (usually true), * need to merge that input in: */ if (_inputPtr < _inputEnd) { in = new MergedStream(_context, in, _inputBuffer, _inputPtr, _inputEnd); } } return new InputStreamReader(in, enc.getJavaName()); } } throw new RuntimeException("Internal error"); // should never get here } public JsonParser constructParser(int features, ObjectCodec codec, BytesToNameCanonicalizer rootByteSymbols, CharsToNameCanonicalizer rootCharSymbols) throws IOException, JsonParseException { JsonEncoding enc = detectEncoding(); // As per [JACKSON-259], may want to fully disable canonicalization: boolean canonicalize = JsonParser.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(features); boolean intern = JsonParser.Feature.INTERN_FIELD_NAMES.enabledIn(features); if (enc == JsonEncoding.UTF8) { /* and without canonicalization, byte-based approach is not performance; just use std UTF-8 reader * (which is ok for larger input; not so hot for smaller; but this is not a common case) */ if (canonicalize) { BytesToNameCanonicalizer can = rootByteSymbols.makeChild(canonicalize, intern); return new Utf8StreamParser(_context, features, _in, codec, can, _inputBuffer, _inputPtr, _inputEnd, _bufferRecyclable); } } return new ReaderBasedParser(_context, features, constructReader(), codec, rootCharSymbols.makeChild(canonicalize, intern)); } /* /********************************************************** /* Encoding detection for data format auto-detection /********************************************************** */ /** * Current implementation is not as thorough as other functionality * ({@link org.codehaus.jackson.impl.ByteSourceBootstrapper}); * supports UTF-8, for example. But it should work, for now, and can * be improved as necessary. * * @since 1.8 */ public static MatchStrength hasJSONFormat(InputAccessor acc) throws IOException { // Ideally we should see "[" or "{"; but if not, we'll accept double-quote (String) // in future could also consider accepting non-standard matches? if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } byte b = acc.nextByte(); // Very first thing, a UTF-8 BOM? if (b == UTF8_BOM_1) { // yes, looks like UTF-8 BOM if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } if (acc.nextByte() != UTF8_BOM_2) { return MatchStrength.NO_MATCH; } if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } if (acc.nextByte() != UTF8_BOM_3) { return MatchStrength.NO_MATCH; } if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } b = acc.nextByte(); } // Then possible leading space int ch = skipSpace(acc, b); if (ch < 0) { return MatchStrength.INCONCLUSIVE; } // First, let's see if it looks like a structured type: if (ch == '{') { // JSON object? // Ideally we need to find either double-quote or closing bracket ch = skipSpace(acc); if (ch < 0) { return MatchStrength.INCONCLUSIVE; } if (ch == '"' || ch == '}') { return MatchStrength.SOLID_MATCH; } // ... should we allow non-standard? Let's not yet... can add if need be return MatchStrength.NO_MATCH; } MatchStrength strength; if (ch == '[') { ch = skipSpace(acc); if (ch < 0) { return MatchStrength.INCONCLUSIVE; } // closing brackets is easy; but for now, let's also accept opening... if (ch == ']' || ch == '[') { return MatchStrength.SOLID_MATCH; } return MatchStrength.SOLID_MATCH; } else { // plain old value is not very convincing... strength = MatchStrength.WEAK_MATCH; } if (ch == '"') { // string value return strength; } if (ch <= '9' && ch >= '0') { // number return strength; } if (ch == '-') { // negative number ch = skipSpace(acc); if (ch < 0) { return MatchStrength.INCONCLUSIVE; } return (ch <= '9' && ch >= '0') ? strength : MatchStrength.NO_MATCH; } // or one of literals if (ch == 'n') { // null return tryMatch(acc, "ull", strength); } if (ch == 't') { // true return tryMatch(acc, "rue", strength); } if (ch == 'f') { // false return tryMatch(acc, "alse", strength); } return MatchStrength.NO_MATCH; } private final static MatchStrength tryMatch(InputAccessor acc, String matchStr, MatchStrength fullMatchStrength) throws IOException { for (int i = 0, len = matchStr.length(); i < len; ++i) { if (!acc.hasMoreBytes()) { return MatchStrength.INCONCLUSIVE; } if (acc.nextByte() != matchStr.charAt(i)) { return MatchStrength.NO_MATCH; } } return fullMatchStrength; } private final static int skipSpace(InputAccessor acc) throws IOException { if (!acc.hasMoreBytes()) { return -1; } return skipSpace(acc, acc.nextByte()); } private final static int skipSpace(InputAccessor acc, byte b) throws IOException { while (true) { int ch = (int) b & 0xFF; if (!(ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t')) { return ch; } if (!acc.hasMoreBytes()) { return -1; } b = acc.nextByte(); ch = (int) b & 0xFF; } } /* /********************************************************** /* Internal methods, parsing /********************************************************** */ /** * @return True if a BOM was succesfully found, and encoding * thereby recognized. */ private boolean handleBOM(int quad) throws IOException { /* Handling of (usually) optional BOM (required for * multi-byte formats); first 32-bit charsets: */ switch (quad) { case 0x0000FEFF: _bigEndian = true; _inputPtr += 4; _bytesPerChar = 4; return true; case 0xFFFE0000: // UCS-4, LE? _inputPtr += 4; _bytesPerChar = 4; _bigEndian = false; return true; case 0x0000FFFE: // UCS-4, in-order... reportWeirdUCS4("2143"); // throws exception case 0xFEFF0000: // UCS-4, in-order... reportWeirdUCS4("3412"); // throws exception } // Ok, if not, how about 16-bit encoding BOMs? int msw = quad >>> 16; if (msw == 0xFEFF) { // UTF-16, BE _inputPtr += 2; _bytesPerChar = 2; _bigEndian = true; return true; } if (msw == 0xFFFE) { // UTF-16, LE _inputPtr += 2; _bytesPerChar = 2; _bigEndian = false; return true; } // And if not, then UTF-8 BOM? if ((quad >>> 8) == 0xEFBBBF) { // UTF-8 _inputPtr += 3; _bytesPerChar = 1; _bigEndian = true; // doesn't really matter return true; } return false; } private boolean checkUTF32(int quad) throws IOException { /* Handling of (usually) optional BOM (required for * multi-byte formats); first 32-bit charsets: */ if ((quad >> 8) == 0) { // 0x000000?? -> UTF32-BE _bigEndian = true; } else if ((quad & 0x00FFFFFF) == 0) { // 0x??000000 -> UTF32-LE _bigEndian = false; } else if ((quad & ~0x00FF0000) == 0) { // 0x00??0000 -> UTF32-in-order reportWeirdUCS4("3412"); } else if ((quad & ~0x0000FF00) == 0) { // 0x0000??00 -> UTF32-in-order reportWeirdUCS4("2143"); } else { // Can not be valid UTF-32 encoded JSON... return false; } // Not BOM (just regular content), nothing to skip past: //_inputPtr += 4; _bytesPerChar = 4; return true; } private boolean checkUTF16(int i16) { if ((i16 & 0xFF00) == 0) { // UTF-16BE _bigEndian = true; } else if ((i16 & 0x00FF) == 0) { // UTF-16LE _bigEndian = false; } else { // nope, not UTF-16 return false; } // Not BOM (just regular content), nothing to skip past: //_inputPtr += 2; _bytesPerChar = 2; return true; } /* /********************************************************** /* Internal methods, problem reporting /********************************************************** */ private void reportWeirdUCS4(String type) throws IOException { throw new CharConversionException("Unsupported UCS-4 endianness ("+type+") detected"); } /* /********************************************************** /* Internal methods, raw input access /********************************************************** */ protected boolean ensureLoaded(int minimum) throws IOException { /* Let's assume here buffer has enough room -- this will always * be true for the limited used this method gets */ int gotten = (_inputEnd - _inputPtr); while (gotten < minimum) { int count; if (_in == null) { // block source count = -1; } else { count = _in.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd); } if (count < 1) { return false; } _inputEnd += count; gotten += count; } return true; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/JsonWriteContext.java0000644000175000017500000001141311655120726027236 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import org.codehaus.jackson.*; /** * Extension of {@link JsonStreamContext}, which implements * core methods needed, and also exposes * more complete API to generator implementation classes. */ public class JsonWriteContext extends JsonStreamContext { // // // Return values for writeValue() public final static int STATUS_OK_AS_IS = 0; public final static int STATUS_OK_AFTER_COMMA = 1; public final static int STATUS_OK_AFTER_COLON = 2; public final static int STATUS_OK_AFTER_SPACE = 3; // in root context public final static int STATUS_EXPECT_VALUE = 4; public final static int STATUS_EXPECT_NAME = 5; protected final JsonWriteContext _parent; /** * Name of the field of which value is to be parsed; only * used for OBJECT contexts */ protected String _currentName; /* /********************************************************** /* Simple instance reuse slots; speed up things /* a bit (10-15%) for docs with lots of small /* arrays/objects /********************************************************** */ protected JsonWriteContext _child = null; /* /********************************************************** /* Life-cycle /********************************************************** */ protected JsonWriteContext(int type, JsonWriteContext parent) { super(); _type = type; _parent = parent; _index = -1; } // // // Factory methods public static JsonWriteContext createRootContext() { return new JsonWriteContext(TYPE_ROOT, null); } private final JsonWriteContext reset(int type) { _type = type; _index = -1; _currentName = null; return this; } public final JsonWriteContext createChildArrayContext() { JsonWriteContext ctxt = _child; if (ctxt == null) { _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this); return ctxt; } return ctxt.reset(TYPE_ARRAY); } public final JsonWriteContext createChildObjectContext() { JsonWriteContext ctxt = _child; if (ctxt == null) { _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this); return ctxt; } return ctxt.reset(TYPE_OBJECT); } // // // Shared API @Override public final JsonWriteContext getParent() { return _parent; } @Override public final String getCurrentName() { return _currentName; } // // // API sub-classes are to implement /** * Method that writer is to call before it writes a field name. * * @return Index of the field entry (0-based) */ public final int writeFieldName(String name) { if (_type == TYPE_OBJECT) { if (_currentName != null) { // just wrote a name... return STATUS_EXPECT_VALUE; } _currentName = name; return (_index < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA; } return STATUS_EXPECT_VALUE; } public final int writeValue() { // Most likely, object: if (_type == TYPE_OBJECT) { if (_currentName == null) { return STATUS_EXPECT_NAME; } _currentName = null; ++_index; return STATUS_OK_AFTER_COLON; } // Ok, array? if (_type == TYPE_ARRAY) { int ix = _index; ++_index; return (ix < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA; } // Nope, root context // No commas within root context, but need space ++_index; return (_index == 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_SPACE; } // // // Internally used abstract methods protected final void appendDesc(StringBuilder sb) { if (_type == TYPE_OBJECT) { sb.append('{'); if (_currentName != null) { sb.append('"'); // !!! TODO: Name chars should be escaped? sb.append(_currentName); sb.append('"'); } else { sb.append('?'); } sb.append('}'); } else if (_type == TYPE_ARRAY) { sb.append('['); sb.append(getCurrentIndex()); sb.append(']'); } else { // nah, ROOT: sb.append("/"); } } // // // Overridden standard methods /** * Overridden to provide developer writeable "JsonPath" representation * of the context. */ @Override public final String toString() { StringBuilder sb = new StringBuilder(64); appendDesc(sb); return sb.toString(); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/WriterBasedGenerator.java0000644000175000017500000016713111655120726030040 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.io.*; import org.codehaus.jackson.util.CharTypes; /** * {@link JsonGenerator} that outputs JSON content using a {@link java.io.Writer} * which handles character encoding. */ public final class WriterBasedGenerator extends JsonGeneratorBase { final protected static int SHORT_WRITE = 32; final protected static char[] HEX_CHARS = CharTypes.copyHexChars(); /** * This is the default set of escape codes, over 7-bit ASCII range * (first 128 character codes), used for single-byte UTF-8 characters. */ protected final static int[] sOutputEscapes = CharTypes.get7BitOutputEscapes(); /* /********************************************************** /* Configuration /********************************************************** */ final protected IOContext _ioContext; final protected Writer _writer; /* /********************************************************** /* Configuration, output escaping /********************************************************** */ /** * Currently active set of output escape code definitions (whether * and how to escape or not) for 7-bit ASCII range (first 128 * character codes). Defined separately to make potentially * customizable */ protected int[] _outputEscapes = sOutputEscapes; /** * Value between 128 (0x80) and 65535 (0xFFFF) that indicates highest * Unicode code point that will not need escaping; or 0 to indicate * that all characters can be represented without escaping. * Typically used to force escaping of some portion of character set; * for example to always escape non-ASCII characters (if value was 127). *

* NOTE: not all sub-classes make use of this setting. */ protected int _maximumNonEscapedChar; /** * Definition of custom character escapes to use for generators created * by this factory, if any. If null, standard data format specific * escapes are used. * * @since 1.8 */ protected CharacterEscapes _characterEscapes; /** * When custom escapes are used, this member variable can be used to * store escape to use * * @since 1.8 */ protected SerializableString _currentEscape; /* /********************************************************** /* Output buffering /********************************************************** */ /** * Intermediate buffer in which contents are buffered before * being written using {@link #_writer}. */ protected char[] _outputBuffer; /** * Pointer to the first buffered character to output */ protected int _outputHead = 0; /** * Pointer to the position right beyond the last character to output * (end marker; may point to position right beyond the end of the buffer) */ protected int _outputTail = 0; /** * End marker of the output buffer; one past the last valid position * within the buffer. */ protected int _outputEnd; /** * Short (14 char) temporary buffer allocated if needed, for constructing * escape sequences */ protected char[] _entityBuffer; /* /********************************************************** /* Life-cycle /********************************************************** */ public WriterBasedGenerator(IOContext ctxt, int features, ObjectCodec codec, Writer w) { super(features, codec); _ioContext = ctxt; _writer = w; _outputBuffer = ctxt.allocConcatBuffer(); _outputEnd = _outputBuffer.length; if (isEnabled(Feature.ESCAPE_NON_ASCII)) { setHighestNonEscapedChar(127); } } /* /********************************************************** /* Overridden configuration methods /********************************************************** */ @Override public JsonGenerator setHighestNonEscapedChar(int charCode) { _maximumNonEscapedChar = (charCode < 0) ? 0 : charCode; return this; } @Override public int getHighestEscapedChar() { return _maximumNonEscapedChar; } @Override public JsonGenerator setCharacterEscapes(CharacterEscapes esc) { _characterEscapes = esc; if (esc == null) { // revert to standard escapes _outputEscapes = sOutputEscapes; } else { _outputEscapes = esc.getEscapeCodesForAscii(); } return this; } /** * Method for accessing custom escapes factory uses for {@link JsonGenerator}s * it creates. * * @since 1.8 */ @Override public CharacterEscapes getCharacterEscapes() { return _characterEscapes; } @Override public Object getOutputTarget() { return _writer; } /* /********************************************************** /* Overridden methods /********************************************************** */ /* Most overrides in this section are just to make methods final, * to allow better inlining... */ @Override public final void writeFieldName(String name) throws IOException, JsonGenerationException { int status = _writeContext.writeFieldName(name); if (status == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA)); } @Override public final void writeStringField(String fieldName, String value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeString(value); } @Override public final void writeFieldName(SerializedString name) throws IOException, JsonGenerationException { // Object is a value, need to verify it's allowed int status = _writeContext.writeFieldName(name.getValue()); if (status == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA)); } @Override public final void writeFieldName(SerializableString name) throws IOException, JsonGenerationException { // Object is a value, need to verify it's allowed int status = _writeContext.writeFieldName(name.getValue()); if (status == JsonWriteContext.STATUS_EXPECT_VALUE) { _reportError("Can not write a field name, expecting a value"); } _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA)); } /* /********************************************************** /* Output method implementations, structural /********************************************************** */ @Override public final void writeStartArray() throws IOException, JsonGenerationException { _verifyValueWrite("start an array"); _writeContext = _writeContext.createChildArrayContext(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeStartArray(this); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '['; } } @Override public final void writeEndArray() throws IOException, JsonGenerationException { if (!_writeContext.inArray()) { _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc()); } if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount()); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = ']'; } _writeContext = _writeContext.getParent(); } @Override public final void writeStartObject() throws IOException, JsonGenerationException { _verifyValueWrite("start an object"); _writeContext = _writeContext.createChildObjectContext(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeStartObject(this); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '{'; } } @Override public final void writeEndObject() throws IOException, JsonGenerationException { if (!_writeContext.inObject()) { _reportError("Current context not an object but "+_writeContext.getTypeDesc()); } _writeContext = _writeContext.getParent(); if (_cfgPrettyPrinter != null) { _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount()); } else { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '}'; } } protected void _writeFieldName(String name, boolean commaBefore) throws IOException, JsonGenerationException { if (_cfgPrettyPrinter != null) { _writePPFieldName(name, commaBefore); return; } // for fast+std case, need to output up to 2 chars, comma, dquote if ((_outputTail + 1) >= _outputEnd) { _flushBuffer(); } if (commaBefore) { _outputBuffer[_outputTail++] = ','; } /* To support [JACKSON-46], we'll do this: * (Question: should quoting of spaces (etc) still be enabled?) */ if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) { _writeString(name); return; } // we know there's room for at least one more char _outputBuffer[_outputTail++] = '"'; // The beef: _writeString(name); // and closing quotes; need room for one more char: if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } public void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException, JsonGenerationException { if (_cfgPrettyPrinter != null) { _writePPFieldName(name, commaBefore); return; } // for fast+std case, need to output up to 2 chars, comma, dquote if ((_outputTail + 1) >= _outputEnd) { _flushBuffer(); } if (commaBefore) { _outputBuffer[_outputTail++] = ','; } /* To support [JACKSON-46], we'll do this: * (Question: should quoting of spaces (etc) still be enabled?) */ final char[] quoted = name.asQuotedChars(); if (!isEnabled(Feature.QUOTE_FIELD_NAMES)) { writeRaw(quoted, 0, quoted.length); return; } // we know there's room for at least one more char _outputBuffer[_outputTail++] = '"'; // The beef: final int qlen = quoted.length; if ((_outputTail + qlen + 1) >= _outputEnd) { writeRaw(quoted, 0, qlen); // and closing quotes; need room for one more char: if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } else { System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen); _outputTail += qlen; _outputBuffer[_outputTail++] = '"'; } } /** * Specialized version of _writeFieldName, off-lined * to keep the "fast path" as simple (and hopefully fast) as possible. */ protected final void _writePPFieldName(String name, boolean commaBefore) throws IOException, JsonGenerationException { if (commaBefore) { _cfgPrettyPrinter.writeObjectEntrySeparator(this); } else { _cfgPrettyPrinter.beforeObjectEntries(this); } if (isEnabled(Feature.QUOTE_FIELD_NAMES)) { // standard if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; _writeString(name); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } else { // non-standard, omit quotes _writeString(name); } } protected final void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException, JsonGenerationException { if (commaBefore) { _cfgPrettyPrinter.writeObjectEntrySeparator(this); } else { _cfgPrettyPrinter.beforeObjectEntries(this); } final char[] quoted = name.asQuotedChars(); if (isEnabled(Feature.QUOTE_FIELD_NAMES)) { // standard if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; writeRaw(quoted, 0, quoted.length); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } else { // non-standard, omit quotes writeRaw(quoted, 0, quoted.length); } } /* /********************************************************** /* Output method implementations, textual /********************************************************** */ @Override public void writeString(String text) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (text == null) { _writeNull(); return; } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; _writeString(text); // And finally, closing quotes if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } @Override public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; _writeString(text, offset, len); // And finally, closing quotes if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } @Override public final void writeString(SerializableString sstr) throws IOException, JsonGenerationException { _verifyValueWrite("write text value"); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; // Note: copied from writeRaw: char[] text = sstr.asQuotedChars(); final int len = text.length; // Only worth buffering if it's a short write? if (len < SHORT_WRITE) { int room = _outputEnd - _outputTail; if (len > room) { _flushBuffer(); } System.arraycopy(text, 0, _outputBuffer, _outputTail, len); _outputTail += len; } else { // Otherwise, better just pass through: _flushBuffer(); _writer.write(text, 0, len); } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } @Override public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException { // could add support for buffering if we really want it... _reportUnsupportedOperation(); } @Override public void writeUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException { // could add support for buffering if we really want it... _reportUnsupportedOperation(); } /* /********************************************************** /* Output method implementations, unprocessed ("raw") /********************************************************** */ @Override public void writeRaw(String text) throws IOException, JsonGenerationException { // Nothing to check, can just output as is int len = text.length(); int room = _outputEnd - _outputTail; if (room == 0) { _flushBuffer(); room = _outputEnd - _outputTail; } // But would it nicely fit in? If yes, it's easy if (room >= len) { text.getChars(0, len, _outputBuffer, _outputTail); _outputTail += len; } else { writeRawLong(text); } } @Override public void writeRaw(String text, int start, int len) throws IOException, JsonGenerationException { // Nothing to check, can just output as is int room = _outputEnd - _outputTail; if (room < len) { _flushBuffer(); room = _outputEnd - _outputTail; } // But would it nicely fit in? If yes, it's easy if (room >= len) { text.getChars(start, start+len, _outputBuffer, _outputTail); _outputTail += len; } else { writeRawLong(text.substring(start, start+len)); } } @Override public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException { // Only worth buffering if it's a short write? if (len < SHORT_WRITE) { int room = _outputEnd - _outputTail; if (len > room) { _flushBuffer(); } System.arraycopy(text, offset, _outputBuffer, _outputTail, len); _outputTail += len; return; } // Otherwise, better just pass through: _flushBuffer(); _writer.write(text, offset, len); } @Override public void writeRaw(char c) throws IOException, JsonGenerationException { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = c; } private void writeRawLong(String text) throws IOException, JsonGenerationException { int room = _outputEnd - _outputTail; // If not, need to do it by looping text.getChars(0, room, _outputBuffer, _outputTail); _outputTail += room; _flushBuffer(); int offset = room; int len = text.length() - room; while (len > _outputEnd) { int amount = _outputEnd; text.getChars(offset, offset+amount, _outputBuffer, 0); _outputHead = 0; _outputTail = amount; _flushBuffer(); offset += amount; len -= amount; } // And last piece (at most length of buffer) text.getChars(offset, offset+len, _outputBuffer, 0); _outputHead = 0; _outputTail = len; } /* /********************************************************** /* Output method implementations, base64-encoded binary /********************************************************** */ @Override public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException, JsonGenerationException { _verifyValueWrite("write binary value"); // Starting quotes if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; _writeBinary(b64variant, data, offset, offset+len); // and closing quotes if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } /* /********************************************************** /* Output method implementations, primitive /********************************************************** */ @Override public void writeNumber(int i) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); // up to 10 digits and possible minus sign if ((_outputTail + 11) >= _outputEnd) { _flushBuffer(); } if (_cfgNumbersAsStrings) { _writeQuotedInt(i); return; } _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); } private final void _writeQuotedInt(int i) throws IOException { if ((_outputTail + 13) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); _outputBuffer[_outputTail++] = '"'; } @Override public void writeNumber(long l) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); if (_cfgNumbersAsStrings) { _writeQuotedLong(l); return; } if ((_outputTail + 21) >= _outputEnd) { // up to 20 digits, minus sign _flushBuffer(); } _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); } private final void _writeQuotedLong(long l) throws IOException { if ((_outputTail + 23) >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); _outputBuffer[_outputTail++] = '"'; } // !!! 05-Aug-2008, tatus: Any ways to optimize these? @Override public void writeNumber(BigInteger value) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); if (value == null) { _writeNull(); } else if (_cfgNumbersAsStrings) { _writeQuotedRaw(value); } else { writeRaw(value.toString()); } } @Override public void writeNumber(double d) throws IOException, JsonGenerationException { if (_cfgNumbersAsStrings || // [JACKSON-139] (((Double.isNaN(d) || Double.isInfinite(d)) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) { writeString(String.valueOf(d)); return; } // What is the max length for doubles? 40 chars? _verifyValueWrite("write number"); writeRaw(String.valueOf(d)); } @Override public void writeNumber(float f) throws IOException, JsonGenerationException { if (_cfgNumbersAsStrings || // [JACKSON-139] (((Float.isNaN(f) || Float.isInfinite(f)) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)))) { writeString(String.valueOf(f)); return; } // What is the max length for floats? _verifyValueWrite("write number"); writeRaw(String.valueOf(f)); } @Override public void writeNumber(BigDecimal value) throws IOException, JsonGenerationException { // Don't really know max length for big decimal, no point checking _verifyValueWrite("write number"); if (value == null) { _writeNull(); } else if (_cfgNumbersAsStrings) { _writeQuotedRaw(value); } else { writeRaw(value.toString()); } } @Override public void writeNumber(String encodedValue) throws IOException, JsonGenerationException { _verifyValueWrite("write number"); if (_cfgNumbersAsStrings) { _writeQuotedRaw(encodedValue); } else { writeRaw(encodedValue); } } private final void _writeQuotedRaw(Object value) throws IOException { if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; writeRaw(value.toString()); if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '"'; } @Override public void writeBoolean(boolean state) throws IOException, JsonGenerationException { _verifyValueWrite("write boolean value"); if ((_outputTail + 5) >= _outputEnd) { _flushBuffer(); } int ptr = _outputTail; char[] buf = _outputBuffer; if (state) { buf[ptr] = 't'; buf[++ptr] = 'r'; buf[++ptr] = 'u'; buf[++ptr] = 'e'; } else { buf[ptr] = 'f'; buf[++ptr] = 'a'; buf[++ptr] = 'l'; buf[++ptr] = 's'; buf[++ptr] = 'e'; } _outputTail = ptr+1; } @Override public void writeNull() throws IOException, JsonGenerationException { _verifyValueWrite("write null value"); _writeNull(); } /* /********************************************************** /* Implementations for other methods /********************************************************** */ @Override protected final void _verifyValueWrite(String typeMsg) throws IOException, JsonGenerationException { int status = _writeContext.writeValue(); if (status == JsonWriteContext.STATUS_EXPECT_NAME) { _reportError("Can not "+typeMsg+", expecting field name"); } if (_cfgPrettyPrinter == null) { char c; switch (status) { case JsonWriteContext.STATUS_OK_AFTER_COMMA: c = ','; break; case JsonWriteContext.STATUS_OK_AFTER_COLON: c = ':'; break; case JsonWriteContext.STATUS_OK_AFTER_SPACE: c = ' '; break; case JsonWriteContext.STATUS_OK_AS_IS: default: return; } if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail] = c; ++_outputTail; return; } // Otherwise, pretty printer knows what to do... _verifyPrettyValueWrite(typeMsg, status); } protected final void _verifyPrettyValueWrite(String typeMsg, int status) throws IOException, JsonGenerationException { // If we have a pretty printer, it knows what to do: switch (status) { case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array _cfgPrettyPrinter.writeArrayValueSeparator(this); break; case JsonWriteContext.STATUS_OK_AFTER_COLON: _cfgPrettyPrinter.writeObjectFieldValueSeparator(this); break; case JsonWriteContext.STATUS_OK_AFTER_SPACE: _cfgPrettyPrinter.writeRootValueSeparator(this); break; case JsonWriteContext.STATUS_OK_AS_IS: // First entry, but of which context? if (_writeContext.inArray()) { _cfgPrettyPrinter.beforeArrayValues(this); } else if (_writeContext.inObject()) { _cfgPrettyPrinter.beforeObjectEntries(this); } break; default: _cantHappen(); break; } } /* /********************************************************** /* Low-level output handling /********************************************************** */ @Override public final void flush() throws IOException { _flushBuffer(); if (_writer != null) { if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) { _writer.flush(); } } } @Override public void close() throws IOException { super.close(); /* 05-Dec-2008, tatu: To add [JACKSON-27], need to close open * scopes. */ // First: let's see that we still have buffers... if (_outputBuffer != null && isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) { while (true) { JsonStreamContext ctxt = getOutputContext(); if (ctxt.inArray()) { writeEndArray(); } else if (ctxt.inObject()) { writeEndObject(); } else { break; } } } _flushBuffer(); /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying Reader, unless we "own" it, or auto-closing * feature is enabled. * One downside: when using UTF8Writer, underlying buffer(s) * may not be properly recycled if we don't close the writer. */ if (_writer != null) { if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) { _writer.close(); } else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) { // If we can't close it, we should at least flush _writer.flush(); } } // Internal buffer(s) generator has can now be released as well _releaseBuffers(); } @Override protected void _releaseBuffers() { char[] buf = _outputBuffer; if (buf != null) { _outputBuffer = null; _ioContext.releaseConcatBuffer(buf); } } /* /********************************************************** /* Internal methods, low-level writing; text, default /********************************************************** */ private void _writeString(String text) throws IOException, JsonGenerationException { /* One check first: if String won't fit in the buffer, let's * segment writes. No point in extending buffer to huge sizes * (like if someone wants to include multi-megabyte base64 * encoded stuff or such) */ final int len = text.length(); if (len > _outputEnd) { // Let's reserve space for entity at begin/end _writeLongString(text); return; } // Ok: we know String will fit in buffer ok // But do we need to flush first? if ((_outputTail + len) > _outputEnd) { _flushBuffer(); } text.getChars(0, len, _outputBuffer, _outputTail); if (_characterEscapes != null) { _writeStringCustom(len); } else if (_maximumNonEscapedChar != 0) { _writeStringASCII(len, _maximumNonEscapedChar); } else { _writeString2(len); } } private void _writeString2(final int len) throws IOException, JsonGenerationException { // And then we'll need to verify need for escaping etc: int end = _outputTail + len; final int[] escCodes = _outputEscapes; final int escLen = escCodes.length; output_loop: while (_outputTail < end) { // Fast loop for chars not needing escaping escape_loop: while (true) { char c = _outputBuffer[_outputTail]; if (c < escLen && escCodes[c] != 0) { break escape_loop; } if (++_outputTail >= end) { break output_loop; } } // Ok, bumped into something that needs escaping. /* First things first: need to flush the buffer. * Inlined, as we don't want to lose tail pointer */ int flushLen = (_outputTail - _outputHead); if (flushLen > 0) { _writer.write(_outputBuffer, _outputHead, flushLen); } /* In any case, tail will be the new start, so hopefully * we have room now. */ char c = _outputBuffer[_outputTail++]; _prependOrWriteCharacterEscape(c, escCodes[c]); } } /** * Method called to write "long strings", strings whose length exceeds * output buffer length. */ private void _writeLongString(String text) throws IOException, JsonGenerationException { // First things first: let's flush the buffer to get some more room _flushBuffer(); // Then we can write final int textLen = text.length(); int offset = 0; do { int max = _outputEnd; int segmentLen = ((offset + max) > textLen) ? (textLen - offset) : max; text.getChars(offset, offset+segmentLen, _outputBuffer, 0); if (_characterEscapes != null) { _writeSegmentCustom(segmentLen); } else if (_maximumNonEscapedChar != 0) { _writeSegmentASCII(segmentLen, _maximumNonEscapedChar); } else { _writeSegment(segmentLen); } offset += segmentLen; } while (offset < textLen); } /** * Method called to output textual context which has been copied * to the output buffer prior to call. If any escaping is needed, * it will also be handled by the method. *

* Note: when called, textual content to write is within output * buffer, right after buffered content (if any). That's why only * length of that text is passed, as buffer and offset are implied. */ private final void _writeSegment(int end) throws IOException, JsonGenerationException { final int[] escCodes = _outputEscapes; final int escLen = escCodes.length; int ptr = 0; int start = ptr; output_loop: while (ptr < end) { // Fast loop for chars not needing escaping char c; while (true) { c = _outputBuffer[ptr]; if (c < escLen && escCodes[c] != 0) { break; } if (++ptr >= end) { break; } } // Ok, bumped into something that needs escaping. /* First things first: need to flush the buffer. * Inlined, as we don't want to lose tail pointer */ int flushLen = (ptr - start); if (flushLen > 0) { _writer.write(_outputBuffer, start, flushLen); if (ptr >= end) { break output_loop; } } ++ptr; // So; either try to prepend (most likely), or write directly: start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCodes[c]); } } /** * This method called when the string content is already in * a char buffer, and need not be copied for processing. */ private final void _writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { if (_characterEscapes != null) { _writeStringCustom(text, offset, len); return; } if (_maximumNonEscapedChar != 0) { _writeStringASCII(text, offset, len, _maximumNonEscapedChar); return; } /* Let's just find longest spans of non-escapable * content, and for each see if it makes sense * to copy them, or write through */ len += offset; // -> len marks the end from now on final int[] escCodes = _outputEscapes; final int escLen = escCodes.length; while (offset < len) { int start = offset; while (true) { char c = text[offset]; if (c < escLen && escCodes[c] != 0) { break; } if (++offset >= len) { break; } } // Short span? Better just copy it to buffer first: int newAmount = offset - start; if (newAmount < SHORT_WRITE) { // Note: let's reserve room for escaped char (up to 6 chars) if ((_outputTail + newAmount) > _outputEnd) { _flushBuffer(); } if (newAmount > 0) { System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount); _outputTail += newAmount; } } else { // Nope: better just write through _flushBuffer(); _writer.write(text, start, newAmount); } // Was this the end? if (offset >= len) { // yup break; } // Nope, need to escape the char. char c = text[offset++]; _appendCharacterEscape(c, escCodes[c]); } } /* /********************************************************** /* Internal methods, low-level writing, text segment /* with additional escaping (ASCII or such) /* (since 1.8; see [JACKSON-102]) /********************************************************** */ /* Same as "_writeString2()", except needs additional escaping * for subset of characters */ private void _writeStringASCII(final int len, final int maxNonEscaped) throws IOException, JsonGenerationException { // And then we'll need to verify need for escaping etc: int end = _outputTail + len; final int[] escCodes = _outputEscapes; final int escLimit = Math.min(escCodes.length, _maximumNonEscapedChar+1); int escCode = 0; output_loop: while (_outputTail < end) { char c; // Fast loop for chars not needing escaping escape_loop: while (true) { c = _outputBuffer[_outputTail]; if (c < escLimit) { escCode = escCodes[c]; if (escCode != 0) { break escape_loop; } } else if (c > maxNonEscaped) { escCode = CharacterEscapes.ESCAPE_STANDARD; break escape_loop; } if (++_outputTail >= end) { break output_loop; } } int flushLen = (_outputTail - _outputHead); if (flushLen > 0) { _writer.write(_outputBuffer, _outputHead, flushLen); } ++_outputTail; _prependOrWriteCharacterEscape(c, escCode); } } private final void _writeSegmentASCII(int end, final int maxNonEscaped) throws IOException, JsonGenerationException { final int[] escCodes = _outputEscapes; final int escLimit = Math.min(escCodes.length, _maximumNonEscapedChar+1); int ptr = 0; int escCode = 0; int start = ptr; output_loop: while (ptr < end) { // Fast loop for chars not needing escaping char c; while (true) { c = _outputBuffer[ptr]; if (c < escLimit) { escCode = escCodes[c]; if (escCode != 0) { break; } } else if (c > maxNonEscaped) { escCode = CharacterEscapes.ESCAPE_STANDARD; break; } if (++ptr >= end) { break; } } int flushLen = (ptr - start); if (flushLen > 0) { _writer.write(_outputBuffer, start, flushLen); if (ptr >= end) { break output_loop; } } ++ptr; start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode); } } private final void _writeStringASCII(char[] text, int offset, int len, final int maxNonEscaped) throws IOException, JsonGenerationException { len += offset; // -> len marks the end from now on final int[] escCodes = _outputEscapes; final int escLimit = Math.min(escCodes.length, maxNonEscaped+1); int escCode = 0; while (offset < len) { int start = offset; char c; while (true) { c = text[offset]; if (c < escLimit) { escCode = escCodes[c]; if (escCode != 0) { break; } } else if (c > maxNonEscaped) { escCode = CharacterEscapes.ESCAPE_STANDARD; break; } if (++offset >= len) { break; } } // Short span? Better just copy it to buffer first: int newAmount = offset - start; if (newAmount < SHORT_WRITE) { // Note: let's reserve room for escaped char (up to 6 chars) if ((_outputTail + newAmount) > _outputEnd) { _flushBuffer(); } if (newAmount > 0) { System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount); _outputTail += newAmount; } } else { // Nope: better just write through _flushBuffer(); _writer.write(text, start, newAmount); } // Was this the end? if (offset >= len) { // yup break; } // Nope, need to escape the char. ++offset; _appendCharacterEscape(c, escCode); } } /* /********************************************************** /* Internal methods, low-level writing, text segment /* with custom escaping (possibly coupling with ASCII limits) /* (since 1.8; see [JACKSON-106]) /********************************************************** */ /* Same as "_writeString2()", except needs additional escaping * for subset of characters */ private void _writeStringCustom(final int len) throws IOException, JsonGenerationException { // And then we'll need to verify need for escaping etc: int end = _outputTail + len; final int[] escCodes = _outputEscapes; final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar; final int escLimit = Math.min(escCodes.length, maxNonEscaped+1); int escCode = 0; final CharacterEscapes customEscapes = _characterEscapes; output_loop: while (_outputTail < end) { char c; // Fast loop for chars not needing escaping escape_loop: while (true) { c = _outputBuffer[_outputTail]; if (c < escLimit) { escCode = escCodes[c]; if (escCode != 0) { break escape_loop; } } else if (c > maxNonEscaped) { escCode = CharacterEscapes.ESCAPE_STANDARD; break escape_loop; } else { if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) { escCode = CharacterEscapes.ESCAPE_CUSTOM; break escape_loop; } } if (++_outputTail >= end) { break output_loop; } } int flushLen = (_outputTail - _outputHead); if (flushLen > 0) { _writer.write(_outputBuffer, _outputHead, flushLen); } ++_outputTail; _prependOrWriteCharacterEscape(c, escCode); } } private final void _writeSegmentCustom(int end) throws IOException, JsonGenerationException { final int[] escCodes = _outputEscapes; final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar; final int escLimit = Math.min(escCodes.length, _maximumNonEscapedChar+1); final CharacterEscapes customEscapes = _characterEscapes; int ptr = 0; int escCode = 0; int start = ptr; output_loop: while (ptr < end) { // Fast loop for chars not needing escaping char c; while (true) { c = _outputBuffer[ptr]; if (c < escLimit) { escCode = escCodes[c]; if (escCode != 0) { break; } } else if (c > maxNonEscaped) { escCode = CharacterEscapes.ESCAPE_STANDARD; break; } else { if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) { escCode = CharacterEscapes.ESCAPE_CUSTOM; break; } } if (++ptr >= end) { break; } } int flushLen = (ptr - start); if (flushLen > 0) { _writer.write(_outputBuffer, start, flushLen); if (ptr >= end) { break output_loop; } } ++ptr; start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode); } } private final void _writeStringCustom(char[] text, int offset, int len) throws IOException, JsonGenerationException { len += offset; // -> len marks the end from now on final int[] escCodes = _outputEscapes; final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar; final int escLimit = Math.min(escCodes.length, maxNonEscaped+1); final CharacterEscapes customEscapes = _characterEscapes; int escCode = 0; while (offset < len) { int start = offset; char c; while (true) { c = text[offset]; if (c < escLimit) { escCode = escCodes[c]; if (escCode != 0) { break; } } else if (c > maxNonEscaped) { escCode = CharacterEscapes.ESCAPE_STANDARD; break; } else { if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) { escCode = CharacterEscapes.ESCAPE_CUSTOM; break; } } if (++offset >= len) { break; } } // Short span? Better just copy it to buffer first: int newAmount = offset - start; if (newAmount < SHORT_WRITE) { // Note: let's reserve room for escaped char (up to 6 chars) if ((_outputTail + newAmount) > _outputEnd) { _flushBuffer(); } if (newAmount > 0) { System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount); _outputTail += newAmount; } } else { // Nope: better just write through _flushBuffer(); _writer.write(text, start, newAmount); } // Was this the end? if (offset >= len) { // yup break; } // Nope, need to escape the char. ++offset; _appendCharacterEscape(c, escCode); } } /* /********************************************************** /* Internal methods, low-level writing; binary /********************************************************** */ protected void _writeBinary(Base64Variant b64variant, byte[] input, int inputPtr, final int inputEnd) throws IOException, JsonGenerationException { // Encoding is by chunks of 3 input, 4 output chars, so: int safeInputEnd = inputEnd - 3; // Let's also reserve room for possible (and quoted) lf char each round int safeOutputEnd = _outputEnd - 6; int chunksBeforeLF = b64variant.getMaxLineLength() >> 2; // Ok, first we loop through all full triplets of data: while (inputPtr <= safeInputEnd) { if (_outputTail > safeOutputEnd) { // need to flush _flushBuffer(); } // First, mash 3 bytes into lsb of 32-bit int int b24 = ((int) input[inputPtr++]) << 8; b24 |= ((int) input[inputPtr++]) & 0xFF; b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF); _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail); if (--chunksBeforeLF <= 0) { // note: must quote in JSON value _outputBuffer[_outputTail++] = '\\'; _outputBuffer[_outputTail++] = 'n'; chunksBeforeLF = b64variant.getMaxLineLength() >> 2; } } // And then we may have 1 or 2 leftover bytes to encode int inputLeft = inputEnd - inputPtr; // 0, 1 or 2 if (inputLeft > 0) { // yes, but do we have room for output? if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but... _flushBuffer(); } int b24 = ((int) input[inputPtr++]) << 16; if (inputLeft == 2) { b24 |= (((int) input[inputPtr++]) & 0xFF) << 8; } _outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail); } } /* /********************************************************** /* Internal methods, low-level writing, other /********************************************************** */ private final void _writeNull() throws IOException { if ((_outputTail + 4) >= _outputEnd) { _flushBuffer(); } int ptr = _outputTail; char[] buf = _outputBuffer; buf[ptr] = 'n'; buf[++ptr] = 'u'; buf[++ptr] = 'l'; buf[++ptr] = 'l'; _outputTail = ptr+1; } /* /********************************************************** /* Internal methods, low-level writing, escapes /********************************************************** */ /** * Method called to try to either prepend character escape at front of * given buffer; or if not possible, to write it out directly. * Uses head and tail pointers (and updates as necessary) */ private final void _prependOrWriteCharacterEscape(char ch, int escCode) throws IOException, JsonGenerationException { if (escCode >= 0) { // \\N (2 char) if (_outputTail >= 2) { // fits, just prepend int ptr = _outputTail - 2; _outputHead = ptr; _outputBuffer[ptr++] = '\\'; _outputBuffer[ptr] = (char) escCode; return; } // won't fit, write char[] buf = _entityBuffer; if (buf == null) { buf = _allocateEntityBuffer(); } _outputHead = _outputTail; buf[1] = (char) escCode; _writer.write(buf, 0, 2); return; } if (escCode != CharacterEscapes.ESCAPE_CUSTOM) { // std, \\uXXXX if (_outputTail >= 6) { // fits, prepend to buffer char[] buf = _outputBuffer; int ptr = _outputTail - 6; _outputHead = ptr; buf[ptr] = '\\'; buf[++ptr] = 'u'; // We know it's a control char, so only the last 2 chars are non-0 if (ch > 0xFF) { // beyond 8 bytes int hi = (ch >> 8) & 0xFF; buf[++ptr] = HEX_CHARS[hi >> 4]; buf[++ptr] = HEX_CHARS[hi & 0xF]; ch &= 0xFF; } else { buf[++ptr] = '0'; buf[++ptr] = '0'; } buf[++ptr] = HEX_CHARS[ch >> 4]; buf[++ptr] = HEX_CHARS[ch & 0xF]; return; } // won't fit, flush and write char[] buf = _entityBuffer; if (buf == null) { buf = _allocateEntityBuffer(); } _outputHead = _outputTail; if (ch > 0xFF) { // beyond 8 bytes int hi = (ch >> 8) & 0xFF; int lo = ch & 0xFF; buf[10] = HEX_CHARS[hi >> 4]; buf[11] = HEX_CHARS[hi & 0xF]; buf[12] = HEX_CHARS[lo >> 4]; buf[13] = HEX_CHARS[lo & 0xF]; _writer.write(buf, 8, 6); } else { // We know it's a control char, so only the last 2 chars are non-0 buf[6] = HEX_CHARS[ch >> 4]; buf[7] = HEX_CHARS[ch & 0xF]; _writer.write(buf, 2, 6); } return; } String escape; if (_currentEscape == null) { escape = _characterEscapes.getEscapeSequence(ch).getValue(); } else { escape = _currentEscape.getValue(); _currentEscape = null; } int len = escape.length(); if (_outputTail >= len) { // fits in, prepend int ptr = _outputTail - len; _outputHead = ptr; escape.getChars(0, len, _outputBuffer, ptr); return; } // won't fit, write separately _outputHead = _outputTail; _writer.write(escape); } /** * Method called to try to either prepend character escape at front of * given buffer; or if not possible, to write it out directly. * * @return Pointer to start of prepended entity (if prepended); or 'ptr' * if not. */ private final int _prependOrWriteCharacterEscape(char[] buffer, int ptr, int end, char ch, int escCode) throws IOException, JsonGenerationException { if (escCode >= 0) { // \\N (2 char) if (ptr > 1 && ptr < end) { // fits, just prepend ptr -= 2; buffer[ptr] = '\\'; buffer[ptr+1] = (char) escCode; } else { // won't fit, write char[] ent = _entityBuffer; if (ent == null) { ent = _allocateEntityBuffer(); } ent[1] = (char) escCode; _writer.write(ent, 0, 2); } return ptr; } if (escCode != CharacterEscapes.ESCAPE_CUSTOM) { // std, \\uXXXX if (ptr > 5 && ptr < end) { // fits, prepend to buffer ptr -= 6; buffer[ptr++] = '\\'; buffer[ptr++] = 'u'; // We know it's a control char, so only the last 2 chars are non-0 if (ch > 0xFF) { // beyond 8 bytes int hi = (ch >> 8) & 0xFF; buffer[ptr++] = HEX_CHARS[hi >> 4]; buffer[ptr++] = HEX_CHARS[hi & 0xF]; ch &= 0xFF; } else { buffer[ptr++] = '0'; buffer[ptr++] = '0'; } buffer[ptr++] = HEX_CHARS[ch >> 4]; buffer[ptr] = HEX_CHARS[ch & 0xF]; ptr -= 5; } else { // won't fit, flush and write char[] ent = _entityBuffer; if (ent == null) { ent = _allocateEntityBuffer(); } _outputHead = _outputTail; if (ch > 0xFF) { // beyond 8 bytes int hi = (ch >> 8) & 0xFF; int lo = ch & 0xFF; ent[10] = HEX_CHARS[hi >> 4]; ent[11] = HEX_CHARS[hi & 0xF]; ent[12] = HEX_CHARS[lo >> 4]; ent[13] = HEX_CHARS[lo & 0xF]; _writer.write(ent, 8, 6); } else { // We know it's a control char, so only the last 2 chars are non-0 ent[6] = HEX_CHARS[ch >> 4]; ent[7] = HEX_CHARS[ch & 0xF]; _writer.write(ent, 2, 6); } } return ptr; } String escape; if (_currentEscape == null) { escape = _characterEscapes.getEscapeSequence(ch).getValue(); } else { escape = _currentEscape.getValue(); _currentEscape = null; } int len = escape.length(); if (ptr >= len && ptr < end) { // fits in, prepend ptr -= len; escape.getChars(0, len, buffer, ptr); } else { // won't fit, write separately _writer.write(escape); } return ptr; } /** * Method called to append escape sequence for given character, at the * end of standard output buffer; or if not possible, write out directly. */ private final void _appendCharacterEscape(char ch, int escCode) throws IOException, JsonGenerationException { if (escCode >= 0) { // \\N (2 char) if ((_outputTail + 2) > _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = '\\'; _outputBuffer[_outputTail++] = (char) escCode; return; } if (escCode != CharacterEscapes.ESCAPE_CUSTOM) { // std, \\uXXXX if ((_outputTail + 2) > _outputEnd) { _flushBuffer(); } int ptr = _outputTail; char[] buf = _outputBuffer; buf[ptr++] = '\\'; buf[ptr++] = 'u'; // We know it's a control char, so only the last 2 chars are non-0 if (ch > 0xFF) { // beyond 8 bytes int hi = (ch >> 8) & 0xFF; buf[ptr++] = HEX_CHARS[hi >> 4]; buf[ptr++] = HEX_CHARS[hi & 0xF]; ch &= 0xFF; } else { buf[ptr++] = '0'; buf[ptr++] = '0'; } buf[ptr++] = HEX_CHARS[ch >> 4]; buf[ptr] = HEX_CHARS[ch & 0xF]; _outputTail = ptr; return; } String escape; if (_currentEscape == null) { escape = _characterEscapes.getEscapeSequence(ch).getValue(); } else { escape = _currentEscape.getValue(); _currentEscape = null; } int len = escape.length(); if ((_outputTail + len) > _outputEnd) { _flushBuffer(); if (len > _outputEnd) { // very very long escape; unlikely but theoretically possible _writer.write(escape); return; } } escape.getChars(0, len, _outputBuffer, _outputTail); _outputTail += len; } private char[] _allocateEntityBuffer() { char[] buf = new char[14]; // first 2 chars, non-numeric escapes (like \n) buf[0] = '\\'; // next 6; 8-bit escapes (control chars mostly) buf[2] = '\\'; buf[3] = 'u'; buf[4] = '0'; buf[5] = '0'; // last 6, beyond 8 bits buf[8] = '\\'; buf[9] = 'u'; _entityBuffer = buf; return buf; } protected final void _flushBuffer() throws IOException { int len = _outputTail - _outputHead; if (len > 0) { int offset = _outputHead; _outputTail = _outputHead = 0; _writer.write(_outputBuffer, offset, len); } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/ReaderBasedParser.java0000644000175000017500000017262411655120726027277 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import java.io.*; import org.codehaus.jackson.*; import org.codehaus.jackson.io.IOContext; import org.codehaus.jackson.sym.CharsToNameCanonicalizer; import org.codehaus.jackson.util.*; /** * This is a concrete implementation of {@link JsonParser}, which is * based on a {@link java.io.Reader} to handle low-level character * conversion tasks. */ public final class ReaderBasedParser extends JsonParserBase { /* /********************************************************** /* Input configuration /********************************************************** */ /** * Reader that can be used for reading more content, if one * buffer from input source, but in some cases pre-loaded buffer * is handed to the parser. */ protected Reader _reader; /** * Current buffer from which data is read; generally data is read into * buffer from input source. */ protected char[] _inputBuffer; /* /********************************************************** /* Configuration /********************************************************** */ protected ObjectCodec _objectCodec; final protected CharsToNameCanonicalizer _symbols; /* /********************************************************** /* Parsing state /********************************************************** */ /** * Flag that indicates that the current token has not yet * been fully processed, and needs to be finished for * some access (or skipped to obtain the next token) */ protected boolean _tokenIncomplete = false; /* /********************************************************** /* Life-cycle /********************************************************** */ public ReaderBasedParser(IOContext ctxt, int features, Reader r, ObjectCodec codec, CharsToNameCanonicalizer st) { super(ctxt, features); _reader = r; _inputBuffer = ctxt.allocTokenBuffer(); _objectCodec = codec; _symbols = st; } /* /********************************************************** /* Base method defs, overrides /********************************************************** */ @Override public ObjectCodec getCodec() { return _objectCodec; } @Override public void setCodec(ObjectCodec c) { _objectCodec = c; } @Override public int releaseBuffered(Writer w) throws IOException { int count = _inputEnd - _inputPtr; if (count < 1) { return 0; } // let's just advance ptr to end int origPtr = _inputPtr; w.write(_inputBuffer, origPtr, count); return count; } @Override public Object getInputSource() { return _reader; } @Override protected final boolean loadMore() throws IOException { _currInputProcessed += _inputEnd; _currInputRowStart -= _inputEnd; if (_reader != null) { int count = _reader.read(_inputBuffer, 0, _inputBuffer.length); if (count > 0) { _inputPtr = 0; _inputEnd = count; return true; } // End of input _closeInput(); // Should never return 0, so let's fail if (count == 0) { throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd); } } return false; } protected char getNextChar(String eofMsg) throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(eofMsg); } } return _inputBuffer[_inputPtr++]; } @Override protected void _closeInput() throws IOException { /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close() * on the underlying Reader, unless we "own" it, or auto-closing * feature is enabled. * One downside is that when using our optimized * Reader (granted, we only do that for UTF-32...) this * means that buffer recycling won't work correctly. */ if (_reader != null) { if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) { _reader.close(); } _reader = null; } } /** * Method called to release internal buffers owned by the base * reader. This may be called along with {@link #_closeInput} (for * example, when explicitly closing this reader instance), or * separately (if need be). */ @Override protected void _releaseBuffers() throws IOException { super._releaseBuffers(); char[] buf = _inputBuffer; if (buf != null) { _inputBuffer = null; _ioContext.releaseTokenBuffer(buf); } } /* /********************************************************** /* Public API, data access /********************************************************** */ /** * Method for accessing textual representation of the current event; * if no current event (before first call to {@link #nextToken}, or * after encountering end-of-input), returns null. * Method can be called for any event. */ @Override public final String getText() throws IOException, JsonParseException { JsonToken t = _currToken; if (t == JsonToken.VALUE_STRING) { if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } return _textBuffer.contentsAsString(); } return _getText2(t); } protected final String _getText2(JsonToken t) { if (t == null) { return null; } switch (t) { case FIELD_NAME: return _parsingContext.getCurrentName(); case VALUE_STRING: // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.contentsAsString(); } return t.asString(); } @Override public char[] getTextCharacters() throws IOException, JsonParseException { if (_currToken != null) { // null only before/after document switch (_currToken) { case FIELD_NAME: if (!_nameCopied) { String name = _parsingContext.getCurrentName(); int nameLen = name.length(); if (_nameCopyBuffer == null) { _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen); } else if (_nameCopyBuffer.length < nameLen) { _nameCopyBuffer = new char[nameLen]; } name.getChars(0, nameLen, _nameCopyBuffer, 0); _nameCopied = true; } return _nameCopyBuffer; case VALUE_STRING: if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.getTextBuffer(); default: return _currToken.asCharArray(); } } return null; } @Override public int getTextLength() throws IOException, JsonParseException { if (_currToken != null) { // null only before/after document switch (_currToken) { case FIELD_NAME: return _parsingContext.getCurrentName().length(); case VALUE_STRING: if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.size(); default: return _currToken.asCharArray().length; } } return 0; } @Override public int getTextOffset() throws IOException, JsonParseException { // Most have offset of 0, only some may have other values: if (_currToken != null) { switch (_currToken) { case FIELD_NAME: return 0; case VALUE_STRING: if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); // only strings can be incomplete } // fall through case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return _textBuffer.getTextOffset(); } } return 0; } @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { if (_currToken != JsonToken.VALUE_STRING && (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) { _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary"); } /* To ensure that we won't see inconsistent data, better clear up * state... */ if (_tokenIncomplete) { try { _binaryValue = _decodeBase64(b64variant); } catch (IllegalArgumentException iae) { throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage()); } /* let's clear incomplete only now; allows for accessing other * textual content in error cases */ _tokenIncomplete = false; } return _binaryValue; } /* /********************************************************** /* Public API, traversal /********************************************************** */ /** * @return Next token from the stream, if any found, or null * to indicate end-of-input */ @Override public JsonToken nextToken() throws IOException, JsonParseException { _numTypesValid = NR_UNKNOWN; /* First: field names are special -- we will always tokenize * (part of) value along with field name to simplify * state handling. If so, can and need to use secondary token: */ if (_currToken == JsonToken.FIELD_NAME) { return _nextAfterName(); } if (_tokenIncomplete) { _skipString(); // only strings can be partial } int i = _skipWSOrEnd(); if (i < 0) { // end-of-input /* 19-Feb-2009, tatu: Should actually close/release things * like input source, symbol table and recyclable buffers now. */ close(); return (_currToken = null); } /* First, need to ensure we know the starting location of token * after skipping leading white space */ _tokenInputTotal = _currInputProcessed + _inputPtr - 1; _tokenInputRow = _currInputRow; _tokenInputCol = _inputPtr - _currInputRowStart - 1; // finally: clear any data retained so far _binaryValue = null; // Closing scope? if (i == INT_RBRACKET) { if (!_parsingContext.inArray()) { _reportMismatchedEndMarker(i, '}'); } _parsingContext = _parsingContext.getParent(); return (_currToken = JsonToken.END_ARRAY); } if (i == INT_RCURLY) { if (!_parsingContext.inObject()) { _reportMismatchedEndMarker(i, ']'); } _parsingContext = _parsingContext.getParent(); return (_currToken = JsonToken.END_OBJECT); } // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { if (i != INT_COMMA) { _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries"); } i = _skipWS(); } /* And should we now have a name? Always true for * Object contexts, since the intermediate 'expect-value' * state is never retained. */ boolean inObject = _parsingContext.inObject(); if (inObject) { // First, field name itself: String name = _parseFieldName(i); _parsingContext.setCurrentName(name); _currToken = JsonToken.FIELD_NAME; i = _skipWS(); if (i != INT_COLON) { _reportUnexpectedChar(i, "was expecting a colon to separate field name and value"); } i = _skipWS(); } // Ok: we must have a value... what is it? JsonToken t; switch (i) { case INT_QUOTE: _tokenIncomplete = true; t = JsonToken.VALUE_STRING; break; case INT_LBRACKET: if (!inObject) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } t = JsonToken.START_ARRAY; break; case INT_LCURLY: if (!inObject) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } t = JsonToken.START_OBJECT; break; case INT_RBRACKET: case INT_RCURLY: // Error: neither is valid at this point; valid closers have // been handled earlier _reportUnexpectedChar(i, "expected a value"); case INT_t: _matchToken("true", 1); t = JsonToken.VALUE_TRUE; break; case INT_f: _matchToken("false", 1); t = JsonToken.VALUE_FALSE; break; case INT_n: _matchToken("null", 1); t = JsonToken.VALUE_NULL; break; case INT_MINUS: /* Should we have separate handling for plus? Although * it is not allowed per se, it may be erroneously used, * and could be indicate by a more specific error message. */ case INT_0: case INT_1: case INT_2: case INT_3: case INT_4: case INT_5: case INT_6: case INT_7: case INT_8: case INT_9: t = parseNumberText(i); break; default: t = _handleUnexpectedValue(i); break; } if (inObject) { _nextToken = t; return _currToken; } _currToken = t; return t; } private final JsonToken _nextAfterName() { _nameCopied = false; // need to invalidate if it was copied JsonToken t = _nextToken; _nextToken = null; // Also: may need to start new context? if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return (_currToken = t); } /* @Override public boolean nextFieldName(SerializableString str) throws IOException, JsonParseException */ // note: identical to one in Utf8StreamParser @Override public String nextTextValue() throws IOException, JsonParseException { if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName' _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_STRING) { if (_tokenIncomplete) { _tokenIncomplete = false; _finishString(); } return _textBuffer.contentsAsString(); } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return null; } // !!! TODO: optimize this case as well return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null; } // note: identical to one in Utf8StreamParser @Override public int nextIntValue(int defaultValue) throws IOException, JsonParseException { if (_currToken == JsonToken.FIELD_NAME) { _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_NUMBER_INT) { return getIntValue(); } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return defaultValue; } // !!! TODO: optimize this case as well return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue; } // note: identical to one in Utf8StreamParser @Override public long nextLongValue(long defaultValue) throws IOException, JsonParseException { if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName' _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_NUMBER_INT) { return getLongValue(); } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return defaultValue; } // !!! TODO: optimize this case as well return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue; } // note: identical to one in Utf8StreamParser @Override public Boolean nextBooleanValue() throws IOException, JsonParseException { if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName' _nameCopied = false; JsonToken t = _nextToken; _nextToken = null; _currToken = t; if (t == JsonToken.VALUE_TRUE) { return Boolean.TRUE; } if (t == JsonToken.VALUE_FALSE) { return Boolean.FALSE; } if (t == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol); } else if (t == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol); } return null; } switch (nextToken()) { case VALUE_TRUE: return Boolean.TRUE; case VALUE_FALSE: return Boolean.FALSE; } return null; } @Override public void close() throws IOException { super.close(); _symbols.release(); } /* /********************************************************** /* Internal methods, number parsing /* (note: in 1.8 and prior, part of "ReaderBasedNumericParser" /********************************************************** */ /** * Initial parsing method for number values. It needs to be able * to parse enough input to be able to determine whether the * value is to be considered a simple integer value, or a more * generic decimal value: latter of which needs to be expressed * as a floating point number. The basic rule is that if the number * has no fractional or exponential part, it is an integer; otherwise * a floating point number. *

* Because much of input has to be processed in any case, no partial * parsing is done: all input text will be stored for further * processing. However, actual numeric value conversion will be * deferred, since it is usually the most complicated and costliest * part of processing. */ protected final JsonToken parseNumberText(int ch) throws IOException, JsonParseException { /* Although we will always be complete with respect to textual * representation (that is, all characters will be parsed), * actual conversion to a number is deferred. Thus, need to * note that no representations are valid yet */ boolean negative = (ch == INT_MINUS); int ptr = _inputPtr; int startPtr = ptr-1; // to include sign/digit already read final int inputLen = _inputEnd; dummy_loop: do { // dummy loop, to be able to break out if (negative) { // need to read the next digit if (ptr >= _inputEnd) { break dummy_loop; } ch = _inputBuffer[ptr++]; // First check: must have a digit to follow minus sign if (ch > INT_9 || ch < INT_0) { _inputPtr = ptr; return _handleInvalidNumberStart(ch, true); } /* (note: has been checked for non-negative already, in * the dispatching code that determined it should be * a numeric value) */ } // One special case, leading zero(es): if (ch == INT_0) { break dummy_loop; } /* First, let's see if the whole number is contained within * the input buffer unsplit. This should be the common case; * and to simplify processing, we will just reparse contents * in the alternative case (number split on buffer boundary) */ int intLen = 1; // already got one // First let's get the obligatory integer part: int_loop: while (true) { if (ptr >= _inputEnd) { break dummy_loop; } ch = (int) _inputBuffer[ptr++]; if (ch < INT_0 || ch > INT_9) { break int_loop; } ++intLen; } int fractLen = 0; // And then see if we get other parts if (ch == INT_DECIMAL_POINT) { // yes, fraction fract_loop: while (true) { if (ptr >= inputLen) { break dummy_loop; } ch = (int) _inputBuffer[ptr++]; if (ch < INT_0 || ch > INT_9) { break fract_loop; } ++fractLen; } // must be followed by sequence of ints, one minimum if (fractLen == 0) { reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); } } int expLen = 0; if (ch == INT_e || ch == INT_E) { // and/or exponent if (ptr >= inputLen) { break dummy_loop; } // Sign indicator? ch = (int) _inputBuffer[ptr++]; if (ch == INT_MINUS || ch == INT_PLUS) { // yup, skip for now if (ptr >= inputLen) { break dummy_loop; } ch = (int) _inputBuffer[ptr++]; } while (ch <= INT_9 && ch >= INT_0) { ++expLen; if (ptr >= inputLen) { break dummy_loop; } ch = (int) _inputBuffer[ptr++]; } // must be followed by sequence of ints, one minimum if (expLen == 0) { reportUnexpectedNumberChar(ch, "Exponent indicator not followed by a digit"); } } // Got it all: let's add to text buffer for parsing, access --ptr; // need to push back following separator _inputPtr = ptr; int len = ptr-startPtr; _textBuffer.resetWithShared(_inputBuffer, startPtr, len); return reset(negative, intLen, fractLen, expLen); } while (false); _inputPtr = negative ? (startPtr+1) : startPtr; return parseNumberText2(negative); } /** * Method called to parse a number, when the primary parse * method has failed to parse it, due to it being split on * buffer boundary. As a result code is very similar, except * that it has to explicitly copy contents to the text buffer * instead of just sharing the main input buffer. */ private final JsonToken parseNumberText2(boolean negative) throws IOException, JsonParseException { char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int outPtr = 0; // Need to prepend sign? if (negative) { outBuf[outPtr++] = '-'; } // This is the place to do leading-zero check(s) too: int intLen = 0; char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : getNextChar("No digit following minus sign"); if (c == '0') { c = _verifyNoLeadingZeroes(); } boolean eof = false; // Ok, first the obligatory integer part: int_loop: while (c >= '0' && c <= '9') { ++intLen; if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = c; if (_inputPtr >= _inputEnd && !loadMore()) { // EOF is legal for main level int values c = CHAR_NULL; eof = true; break int_loop; } c = _inputBuffer[_inputPtr++]; } // Also, integer part is not optional if (intLen == 0) { reportInvalidNumber("Missing integer part (next char "+_getCharDesc(c)+")"); } int fractLen = 0; // And then see if we get other parts if (c == '.') { // yes, fraction outBuf[outPtr++] = c; fract_loop: while (true) { if (_inputPtr >= _inputEnd && !loadMore()) { eof = true; break fract_loop; } c = _inputBuffer[_inputPtr++]; if (c < INT_0 || c > INT_9) { break fract_loop; } ++fractLen; if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = c; } // must be followed by sequence of ints, one minimum if (fractLen == 0) { reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); } } int expLen = 0; if (c == 'e' || c == 'E') { // exponent? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = c; // Not optional, can require that we get one more char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : getNextChar("expected a digit for number exponent"); // Sign indicator? if (c == '-' || c == '+') { if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = c; // Likewise, non optional: c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : getNextChar("expected a digit for number exponent"); } exp_loop: while (c <= INT_9 && c >= INT_0) { ++expLen; if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } outBuf[outPtr++] = c; if (_inputPtr >= _inputEnd && !loadMore()) { eof = true; break exp_loop; } c = _inputBuffer[_inputPtr++]; } // must be followed by sequence of ints, one minimum if (expLen == 0) { reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit"); } } // Ok; unless we hit end-of-input, need to push last char read back if (!eof) { --_inputPtr; } _textBuffer.setCurrentLength(outPtr); // And there we have it! return reset(negative, intLen, fractLen, expLen); } /** * Method called when we have seen one zero, and want to ensure * it is not followed by another */ private final char _verifyNoLeadingZeroes() throws IOException, JsonParseException { // Ok to have plain "0" if (_inputPtr >= _inputEnd && !loadMore()) { return '0'; } char ch = _inputBuffer[_inputPtr]; // if not followed by a number (probably '.'); return zero as is, to be included if (ch < '0' || ch > '9') { return '0'; } if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) { reportInvalidNumber("Leading zeroes not allowed"); } // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number) ++_inputPtr; // Leading zero to be skipped if (ch == INT_0) { while (_inputPtr < _inputEnd || loadMore()) { ch = _inputBuffer[_inputPtr]; if (ch < '0' || ch > '9') { // followed by non-number; retain one zero return '0'; } ++_inputPtr; // skip previous zero if (ch != '0') { // followed by other number; return break; } } } return ch; } /** * Method called if expected numeric value (due to leading sign) does not * look like a number */ protected JsonToken _handleInvalidNumberStart(int ch, boolean negative) throws IOException, JsonParseException { if (ch == 'I') { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOFInValue(); } } ch = _inputBuffer[_inputPtr++]; if (ch == 'N') { String match = negative ? "-INF" :"+INF"; _matchToken(match, 3); if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY); } _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow"); } else if (ch == 'n') { String match = negative ? "-Infinity" :"+Infinity"; _matchToken(match, 3); if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY); } _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow"); } } reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value"); return null; } /* /********************************************************** /* Internal methods, secondary parsing /********************************************************** */ protected final String _parseFieldName(int i) throws IOException, JsonParseException { if (i != INT_QUOTE) { return _handleUnusualFieldName(i); } /* First: let's try to see if we have a simple name: one that does * not cross input buffer boundary, and does not contain escape * sequences. */ int ptr = _inputPtr; int hash = 0; final int inputLen = _inputEnd; if (ptr < inputLen) { final int[] codes = CharTypes.getInputCodeLatin1(); final int maxCode = codes.length; do { int ch = _inputBuffer[ptr]; if (ch < maxCode && codes[ch] != 0) { if (ch == '"') { int start = _inputPtr; _inputPtr = ptr+1; // to skip the quote return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); } break; } hash = (hash * 31) + ch; ++ptr; } while (ptr < inputLen); } int start = _inputPtr; _inputPtr = ptr; return _parseFieldName2(start, hash, INT_QUOTE); } private String _parseFieldName2(int startPtr, int hash, int endChar) throws IOException, JsonParseException { _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr)); /* Output pointers; calls will also ensure that the buffer is * not shared and has room for at least one more char. */ char[] outBuf = _textBuffer.getCurrentSegment(); int outPtr = _textBuffer.getCurrentSegmentSize(); while (true) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(": was expecting closing '"+((char) endChar)+"' for name"); } } char c = _inputBuffer[_inputPtr++]; int i = (int) c; if (i <= INT_BACKSLASH) { if (i == INT_BACKSLASH) { /* Although chars outside of BMP are to be escaped as * an UTF-16 surrogate pair, does that affect decoding? * For now let's assume it does not. */ c = _decodeEscaped(); } else if (i <= endChar) { if (i == endChar) { break; } if (i < INT_SPACE) { _throwUnquotedSpace(i, "name"); } } } hash = (hash * 31) + i; // Ok, let's add char to output: outBuf[outPtr++] = c; // Need more room? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } } _textBuffer.setCurrentLength(outPtr); { TextBuffer tb = _textBuffer; char[] buf = tb.getTextBuffer(); int start = tb.getTextOffset(); int len = tb.size(); return _symbols.findSymbol(buf, start, len, hash); } } /** * Method called when we see non-white space character other * than double quote, when expecting a field name. * In standard mode will just throw an expection; but * in non-standard modes may be able to parse name. * * @since 1.2 */ protected final String _handleUnusualFieldName(int i) throws IOException, JsonParseException { // [JACKSON-173]: allow single quotes if (i == INT_APOSTROPHE && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { return _parseApostropheFieldName(); } // [JACKSON-69]: allow unquoted names if feature enabled: if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) { _reportUnexpectedChar(i, "was expecting double-quote to start field name"); } final int[] codes = CharTypes.getInputCodeLatin1JsNames(); final int maxCode = codes.length; // Also: first char must be a valid name char, but NOT be number boolean firstOk; if (i < maxCode) { // identifier, and not a number firstOk = (codes[i] == 0) && (i < INT_0 || i > INT_9); } else { firstOk = Character.isJavaIdentifierPart((char) i); } if (!firstOk) { _reportUnexpectedChar(i, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name"); } int ptr = _inputPtr; int hash = 0; final int inputLen = _inputEnd; if (ptr < inputLen) { do { int ch = _inputBuffer[ptr]; if (ch < maxCode) { if (codes[ch] != 0) { int start = _inputPtr-1; // -1 to bring back first char _inputPtr = ptr; return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); } } else if (!Character.isJavaIdentifierPart((char) ch)) { int start = _inputPtr-1; // -1 to bring back first char _inputPtr = ptr; return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); } hash = (hash * 31) + ch; ++ptr; } while (ptr < inputLen); } int start = _inputPtr-1; _inputPtr = ptr; return _parseUnusualFieldName2(start, hash, codes); } protected final String _parseApostropheFieldName() throws IOException, JsonParseException { // Note: mostly copy of_parseFieldName int ptr = _inputPtr; int hash = 0; final int inputLen = _inputEnd; if (ptr < inputLen) { final int[] codes = CharTypes.getInputCodeLatin1(); final int maxCode = codes.length; do { int ch = _inputBuffer[ptr]; if (ch == '\'') { int start = _inputPtr; _inputPtr = ptr+1; // to skip the quote return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash); } if (ch < maxCode && codes[ch] != 0) { break; } hash = (hash * 31) + ch; ++ptr; } while (ptr < inputLen); } int start = _inputPtr; _inputPtr = ptr; return _parseFieldName2(start, hash, INT_APOSTROPHE); } /** * Method for handling cases where first non-space character * of an expected value token is not legal for standard JSON content. * * @since 1.3 */ protected final JsonToken _handleUnexpectedValue(int i) throws IOException, JsonParseException { // Most likely an error, unless we are to allow single-quote-strings switch (i) { case '\'': /* [JACKSON-173]: allow single quotes. Unlike with regular * Strings, we'll eagerly parse contents; this so that there's * no need to store information on quote char used. * * Also, no separation to fast/slow parsing; we'll just do * one regular (~= slowish) parsing, to keep code simple */ if (isEnabled(Feature.ALLOW_SINGLE_QUOTES)) { return _handleApostropheValue(); } break; case 'N': _matchToken("NaN", 1); if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { return resetAsNaN("NaN", Double.NaN); } _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow"); break; case '+': // note: '-' is taken as number if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOFInValue(); } } return _handleInvalidNumberStart(_inputBuffer[_inputPtr++], false); } _reportUnexpectedChar(i, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')"); return null; } /** * @since 1.8 */ protected final JsonToken _handleApostropheValue() throws IOException, JsonParseException { char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int outPtr = _textBuffer.getCurrentSegmentSize(); while (true) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(": was expecting closing quote for a string value"); } } char c = _inputBuffer[_inputPtr++]; int i = (int) c; if (i <= INT_BACKSLASH) { if (i == INT_BACKSLASH) { /* Although chars outside of BMP are to be escaped as * an UTF-16 surrogate pair, does that affect decoding? * For now let's assume it does not. */ c = _decodeEscaped(); } else if (i <= INT_APOSTROPHE) { if (i == INT_APOSTROPHE) { break; } if (i < INT_SPACE) { _throwUnquotedSpace(i, "string value"); } } } // Need more room? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } // Ok, let's add char to output: outBuf[outPtr++] = c; } _textBuffer.setCurrentLength(outPtr); return JsonToken.VALUE_STRING; } /** * @since 1.2 */ private String _parseUnusualFieldName2(int startPtr, int hash, int[] codes) throws IOException, JsonParseException { _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr)); char[] outBuf = _textBuffer.getCurrentSegment(); int outPtr = _textBuffer.getCurrentSegmentSize(); final int maxCode = codes.length; while (true) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { // acceptable for now (will error out later) break; } } char c = _inputBuffer[_inputPtr]; int i = (int) c; if (i <= maxCode) { if (codes[i] != 0) { break; } } else if (!Character.isJavaIdentifierPart(c)) { break; } ++_inputPtr; hash = (hash * 31) + i; // Ok, let's add char to output: outBuf[outPtr++] = c; // Need more room? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } } _textBuffer.setCurrentLength(outPtr); { TextBuffer tb = _textBuffer; char[] buf = tb.getTextBuffer(); int start = tb.getTextOffset(); int len = tb.size(); return _symbols.findSymbol(buf, start, len, hash); } } @Override protected void _finishString() throws IOException, JsonParseException { /* First: let's try to see if we have simple String value: one * that does not cross input buffer boundary, and does not * contain escape sequences. */ int ptr = _inputPtr; final int inputLen = _inputEnd; if (ptr < inputLen) { final int[] codes = CharTypes.getInputCodeLatin1(); final int maxCode = codes.length; do { int ch = _inputBuffer[ptr]; if (ch < maxCode && codes[ch] != 0) { if (ch == '"') { _textBuffer.resetWithShared(_inputBuffer, _inputPtr, (ptr-_inputPtr)); _inputPtr = ptr+1; // Yes, we got it all return; } break; } ++ptr; } while (ptr < inputLen); } /* Either ran out of input, or bumped into an escape * sequence... */ _textBuffer.resetWithCopy(_inputBuffer, _inputPtr, (ptr-_inputPtr)); _inputPtr = ptr; _finishString2(); } protected void _finishString2() throws IOException, JsonParseException { char[] outBuf = _textBuffer.getCurrentSegment(); int outPtr = _textBuffer.getCurrentSegmentSize(); while (true) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(": was expecting closing quote for a string value"); } } char c = _inputBuffer[_inputPtr++]; int i = (int) c; if (i <= INT_BACKSLASH) { if (i == INT_BACKSLASH) { /* Although chars outside of BMP are to be escaped as * an UTF-16 surrogate pair, does that affect decoding? * For now let's assume it does not. */ c = _decodeEscaped(); } else if (i <= INT_QUOTE) { if (i == INT_QUOTE) { break; } if (i < INT_SPACE) { _throwUnquotedSpace(i, "string value"); } } } // Need more room? if (outPtr >= outBuf.length) { outBuf = _textBuffer.finishCurrentSegment(); outPtr = 0; } // Ok, let's add char to output: outBuf[outPtr++] = c; } _textBuffer.setCurrentLength(outPtr); } /** * Method called to skim through rest of unparsed String value, * if it is not needed. This can be done bit faster if contents * need not be stored for future access. */ protected void _skipString() throws IOException, JsonParseException { _tokenIncomplete = false; int inputPtr = _inputPtr; int inputLen = _inputEnd; char[] inputBuffer = _inputBuffer; while (true) { if (inputPtr >= inputLen) { _inputPtr = inputPtr; if (!loadMore()) { _reportInvalidEOF(": was expecting closing quote for a string value"); } inputPtr = _inputPtr; inputLen = _inputEnd; } char c = inputBuffer[inputPtr++]; int i = (int) c; if (i <= INT_BACKSLASH) { if (i == INT_BACKSLASH) { /* Although chars outside of BMP are to be escaped as * an UTF-16 surrogate pair, does that affect decoding? * For now let's assume it does not. */ _inputPtr = inputPtr; c = _decodeEscaped(); inputPtr = _inputPtr; inputLen = _inputEnd; } else if (i <= INT_QUOTE) { if (i == INT_QUOTE) { _inputPtr = inputPtr; break; } if (i < INT_SPACE) { _inputPtr = inputPtr; _throwUnquotedSpace(i, "string value"); } } } } } /* /********************************************************** /* Internal methods, other parsing /********************************************************** */ /** * We actually need to check the character value here * (to see if we have \n following \r). */ protected final void _skipCR() throws IOException { if (_inputPtr < _inputEnd || loadMore()) { if (_inputBuffer[_inputPtr] == '\n') { ++_inputPtr; } } ++_currInputRow; _currInputRowStart = _inputPtr; } protected final void _skipLF() throws IOException { ++_currInputRow; _currInputRowStart = _inputPtr; } private final int _skipWS() throws IOException, JsonParseException { while (_inputPtr < _inputEnd || loadMore()) { int i = (int) _inputBuffer[_inputPtr++]; if (i > INT_SPACE) { if (i != INT_SLASH) { return i; } _skipComment(); } else if (i != INT_SPACE) { if (i == INT_LF) { _skipLF(); } else if (i == INT_CR) { _skipCR(); } else if (i != INT_TAB) { _throwInvalidSpace(i); } } } throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries"); } private final int _skipWSOrEnd() throws IOException, JsonParseException { while ((_inputPtr < _inputEnd) || loadMore()) { int i = (int) _inputBuffer[_inputPtr++]; if (i > INT_SPACE) { if (i == INT_SLASH) { _skipComment(); continue; } return i; } if (i != INT_SPACE) { if (i == INT_LF) { _skipLF(); } else if (i == INT_CR) { _skipCR(); } else if (i != INT_TAB) { _throwInvalidSpace(i); } } } // We ran out of input... _handleEOF(); return -1; } private final void _skipComment() throws IOException, JsonParseException { if (!isEnabled(Feature.ALLOW_COMMENTS)) { _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)"); } // First: check which comment (if either) it is: if (_inputPtr >= _inputEnd && !loadMore()) { _reportInvalidEOF(" in a comment"); } char c = _inputBuffer[_inputPtr++]; if (c == '/') { _skipCppComment(); } else if (c == '*') { _skipCComment(); } else { _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment"); } } private final void _skipCComment() throws IOException, JsonParseException { // Ok: need the matching '*/' main_loop: while ((_inputPtr < _inputEnd) || loadMore()) { int i = (int) _inputBuffer[_inputPtr++]; if (i <= INT_ASTERISK) { if (i == INT_ASTERISK) { // end? if ((_inputPtr >= _inputEnd) && !loadMore()) { break main_loop; } if (_inputBuffer[_inputPtr] == INT_SLASH) { ++_inputPtr; return; } continue; } if (i < INT_SPACE) { if (i == INT_LF) { _skipLF(); } else if (i == INT_CR) { _skipCR(); } else if (i != INT_TAB) { _throwInvalidSpace(i); } } } } _reportInvalidEOF(" in a comment"); } private final void _skipCppComment() throws IOException, JsonParseException { // Ok: need to find EOF or linefeed while ((_inputPtr < _inputEnd) || loadMore()) { int i = (int) _inputBuffer[_inputPtr++]; if (i < INT_SPACE) { if (i == INT_LF) { _skipLF(); break; } else if (i == INT_CR) { _skipCR(); break; } else if (i != INT_TAB) { _throwInvalidSpace(i); } } } } @Override protected final char _decodeEscaped() throws IOException, JsonParseException { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in character escape sequence"); } } char c = _inputBuffer[_inputPtr++]; switch ((int) c) { // First, ones that are mapped case INT_b: return '\b'; case INT_t: return '\t'; case INT_n: return '\n'; case INT_f: return '\f'; case INT_r: return '\r'; // And these are to be returned as they are case INT_QUOTE: case INT_SLASH: case INT_BACKSLASH: return c; case INT_u: // and finally hex-escaped break; default: return _handleUnrecognizedCharacterEscape(c); } // Ok, a hex escape. Need 4 characters int value = 0; for (int i = 0; i < 4; ++i) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOF(" in character escape sequence"); } } int ch = (int) _inputBuffer[_inputPtr++]; int digit = CharTypes.charToHex(ch); if (digit < 0) { _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence"); } value = (value << 4) | digit; } return (char) value; } /** * Helper method for checking whether input matches expected token * * @since 1.8 */ protected final void _matchToken(String matchStr, int i) throws IOException, JsonParseException { final int len = matchStr.length(); do { if (_inputPtr >= _inputEnd) { if (!loadMore()) { _reportInvalidEOFInValue(); } } if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) { _reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN"); } ++_inputPtr; } while (++i < len); // but let's also ensure we either get EOF, or non-alphanum char... if (_inputPtr >= _inputEnd) { if (!loadMore()) { return; } } char c = _inputBuffer[_inputPtr]; if (c < '0' || c == ']' || c == '}') { // expected/allowed chars return; } // if Java letter, it's a problem tho if (Character.isJavaIdentifierPart(c)) { ++_inputPtr; _reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN"); } return; } /* /********************************************************** /* Binary access /********************************************************** */ @Override protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException, JsonParseException { ByteArrayBuilder builder = _getByteArrayBuilder(); //main_loop: while (true) { // first, we'll skip preceding white space, if any char ch; do { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++]; } while (ch <= INT_SPACE); int bits = b64variant.decodeBase64Char(ch); if (bits < 0) { if (ch == '"') { // reached the end, fair and square? return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 0); if (bits < 0) { // white space to skip continue; } } int decodedData = bits; // then second base64 char; can't get padding yet, nor ws if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++]; bits = b64variant.decodeBase64Char(ch); if (bits < 0) { bits = _decodeBase64Escape(b64variant, ch, 1); } decodedData = (decodedData << 6) | bits; // third base64 char; can be padding, but not ws if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++]; bits = b64variant.decodeBase64Char(ch); // First branch: can get padding (-> 1 byte) if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { // as per [JACKSON-631], could also just be 'missing' padding if (ch == '"' && !b64variant.usesPadding()) { decodedData >>= 4; builder.append(decodedData); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 2); } if (bits == Base64Variant.BASE64_VALUE_PADDING) { // Ok, must get more padding chars, then if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++]; if (!b64variant.usesPaddingChar(ch)) { throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'"); } // Got 12 bits, only need 8, need to shift decodedData >>= 4; builder.append(decodedData); continue; } // otherwise we got escaped other char, to be processed below } // Nope, 2 or 3 bytes decodedData = (decodedData << 6) | bits; // fourth and last base64 char; can be padding, but not ws if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++]; bits = b64variant.decodeBase64Char(ch); if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { // as per [JACKSON-631], could also just be 'missing' padding if (ch == '"' && !b64variant.usesPadding()) { decodedData >>= 2; builder.appendTwoBytes(decodedData); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 3); } if (bits == Base64Variant.BASE64_VALUE_PADDING) { /* With padding we only get 2 bytes; but we have * to shift it a bit so it is identical to triplet * case with partial output. * 3 chars gives 3x6 == 18 bits, of which 2 are * dummies, need to discard: */ decodedData >>= 2; builder.appendTwoBytes(decodedData); continue; } // otherwise we got escaped other char, to be processed below } // otherwise, our triplet is now complete decodedData = (decodedData << 6) | bits; builder.appendThreeBytes(decodedData); } } /* /********************************************************** /* Error reporting /********************************************************** */ protected void _reportInvalidToken(String matchedPart, String msg) throws IOException, JsonParseException { StringBuilder sb = new StringBuilder(matchedPart); /* Let's just try to find what appears to be the token, using * regular Java identifier character rules. It's just a heuristic, * nothing fancy here. */ while (true) { if (_inputPtr >= _inputEnd) { if (!loadMore()) { break; } } char c = _inputBuffer[_inputPtr]; if (!Character.isJavaIdentifierPart(c)) { break; } ++_inputPtr; sb.append(c); } _reportError("Unrecognized token '"+sb.toString()+"': was expecting "); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/impl/JsonReadContext.java0000644000175000017500000001200611655120726027016 0ustar jamespagejamespagepackage org.codehaus.jackson.impl; import org.codehaus.jackson.*; import org.codehaus.jackson.util.CharTypes; /** * Extension of {@link JsonStreamContext}, which implements * core methods needed, and also exposes * more complete API to parser implementation classes. */ public final class JsonReadContext extends JsonStreamContext { // // // Configuration protected final JsonReadContext _parent; // // // Location information (minus source reference) protected int _lineNr; protected int _columnNr; protected String _currentName; /* /********************************************************** /* Simple instance reuse slots; speeds up things /* a bit (10-15%) for docs with lots of small /* arrays/objects (for which allocation was /* visible in profile stack frames) /********************************************************** */ protected JsonReadContext _child = null; /* /********************************************************** /* Instance construction, reuse /********************************************************** */ public JsonReadContext(JsonReadContext parent, int type, int lineNr, int colNr) { super(); _type = type; _parent = parent; _lineNr = lineNr; _columnNr = colNr; _index = -1; } protected final void reset(int type, int lineNr, int colNr) { _type = type; _index = -1; _lineNr = lineNr; _columnNr = colNr; _currentName = null; } // // // Factory methods public static JsonReadContext createRootContext(int lineNr, int colNr) { return new JsonReadContext(null, TYPE_ROOT, lineNr, colNr); } /** * @since 1.9 */ public static JsonReadContext createRootContext() { return new JsonReadContext(null, TYPE_ROOT, 1, 0); } public final JsonReadContext createChildArrayContext(int lineNr, int colNr) { JsonReadContext ctxt = _child; if (ctxt == null) { _child = ctxt = new JsonReadContext(this, TYPE_ARRAY, lineNr, colNr); return ctxt; } ctxt.reset(TYPE_ARRAY, lineNr, colNr); return ctxt; } public final JsonReadContext createChildObjectContext(int lineNr, int colNr) { JsonReadContext ctxt = _child; if (ctxt == null) { _child = ctxt = new JsonReadContext(this, TYPE_OBJECT, lineNr, colNr); return ctxt; } ctxt.reset(TYPE_OBJECT, lineNr, colNr); return ctxt; } /* /********************************************************** /* Abstract method implementation /********************************************************** */ @Override public final String getCurrentName() { return _currentName; } @Override public final JsonReadContext getParent() { return _parent; } /* /********************************************************** /* Extended API /********************************************************** */ /** * @return Location pointing to the point where the context * start marker was found */ public final JsonLocation getStartLocation(Object srcRef) { /* We don't keep track of offsets at this level (only * reader does) */ long totalChars = -1L; return new JsonLocation(srcRef, totalChars, _lineNr, _columnNr); } /* /********************************************************** /* State changes /********************************************************** */ public final boolean expectComma() { /* Assumption here is that we will be getting a value (at least * before calling this method again), and * so will auto-increment index to avoid having to do another call */ int ix = ++_index; // starts from -1 return (_type != TYPE_ROOT && ix > 0); } public void setCurrentName(String name) { _currentName = name; } /* /********************************************************** /* Overridden standard methods /********************************************************** */ /** * Overridden to provide developer readable "JsonPath" representation * of the context. */ @Override public final String toString() { StringBuilder sb = new StringBuilder(64); switch (_type) { case TYPE_ROOT: sb.append("/"); break; case TYPE_ARRAY: sb.append('['); sb.append(getCurrentIndex()); sb.append(']'); break; case TYPE_OBJECT: sb.append('{'); if (_currentName != null) { sb.append('"'); CharTypes.appendQuoted(sb, _currentName); sb.append('"'); } else { sb.append('?'); } sb.append('}'); break; } return sb.toString(); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonToken.java0000644000175000017500000001141311655120726024716 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Enumeration for basic token types used for returning results * of parsing JSON content. */ public enum JsonToken { /* Some notes on implementation: * * - Entries are to be ordered such that start/end array/object * markers come first, then field name marker (if any), and * finally scalar value tokens. This is assumed by some * typing checks. */ /** * NOT_AVAILABLE can be returned if {@link JsonParser} * implementation can not currently return the requested * token (usually next one), or even if any will be * available, but that may be able to determine this in * future. This is the case with non-blocking parsers -- * they can not block to wait for more data to parse and * must return something. * * @since 0.9.7 */ NOT_AVAILABLE(null), /** * START_OBJECT is returned when encountering '{' * which signals starting of an Object value. */ START_OBJECT("{"), /** * START_OBJECT is returned when encountering '}' * which signals ending of an Object value */ END_OBJECT("}"), /** * START_OBJECT is returned when encountering '[' * which signals starting of an Array value */ START_ARRAY("["), /** * START_OBJECT is returned when encountering ']' * which signals ending of an Array value */ END_ARRAY("]"), /** * FIELD_NAME is returned when a String token is encountered * as a field name (same lexical value, different function) */ FIELD_NAME(null), /** * Placeholder token returned when the input source has a concept * of embedded Object that are not accessible as usual structure * (of starting with {@link #START_OBJECT}, having values, ending with * {@link #END_OBJECT}), but as "raw" objects. *

* Note: this token is never returned by regular JSON readers, but * only by readers that expose other kinds of source (like * {@link JsonNode}-based JSON trees, Maps, Lists and such). * * @since 1.1 */ VALUE_EMBEDDED_OBJECT(null), /** * VALUE_STRING is returned when a String token is encountered * in value context (array element, field value, or root-level * stand-alone value) */ VALUE_STRING(null), /** * VALUE_NUMBER_INT is returned when an integer numeric token is * encountered in value context: that is, a number that does * not have floating point or exponent marker in it (consists * only of an optional sign, followed by one or more digits) */ VALUE_NUMBER_INT(null), /** * VALUE_NUMBER_INT is returned when a numeric token other * that is not an integer is encountered: that is, a number that does * have floating point or exponent marker in it, in addition * to one or more digits. */ VALUE_NUMBER_FLOAT(null), /** * VALUE_TRUE is returned when encountering literal "true" in * value context */ VALUE_TRUE("true"), /** * VALUE_FALSE is returned when encountering literal "false" in * value context */ VALUE_FALSE("false"), /** * VALUE_NULL is returned when encountering literal "null" in * value context */ VALUE_NULL("null") ; final String _serialized; final char[] _serializedChars; final byte[] _serializedBytes; /** * @param Textual representation for this token, if there is a * single static representation; null otherwise */ JsonToken(String token) { if (token == null) { _serialized = null; _serializedChars = null; _serializedBytes = null; } else { _serialized = token; _serializedChars = token.toCharArray(); // It's all in ascii, can just case... int len = _serializedChars.length; _serializedBytes = new byte[len]; for (int i = 0; i < len; ++i) { _serializedBytes[i] = (byte) _serializedChars[i]; } } } public String asString() { return _serialized; } public char[] asCharArray() { return _serializedChars; } public byte[] asByteArray() { return _serializedBytes; } public boolean isNumeric() { return (this == VALUE_NUMBER_INT) || (this == VALUE_NUMBER_FLOAT); } /** * Method that can be used to check whether this token represents * a valid non-structured value. This means all tokens other than * Object/Array start/end markers all field names. */ public boolean isScalarValue() { // note: up to 1.5, VALUE_EMBEDDED_OBJECT was incorrectly considered non-scalar! return ordinal() >= VALUE_EMBEDDED_OBJECT.ordinal(); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/format/0000755000175000017500000000000011672662540023435 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/format/DataFormatDetector.java0000644000175000017500000001400211655120726030005 0ustar jamespagejamespagepackage org.codehaus.jackson.format; import java.io.*; import java.util.*; import org.codehaus.jackson.*; /** * Simple helper class that allows data format (content type) auto-detection, * given an ordered set of {@link JsonFactory} instances to use for actual low-level * detection. * * @since 1.7 */ public class DataFormatDetector { /** * By default we will look ahead at most 64 bytes; in most cases, * much less (4 bytes or so) is needed, but we will allow bit more * leniency to support data formats that need more complex heuristics. */ public final static int DEFAULT_MAX_INPUT_LOOKAHEAD = 64; /** * Ordered list of factories which both represent data formats to * detect (in precedence order, starting with highest) and are used * for actual detection. */ protected final JsonFactory[] _detectors; /** * Strength of match we consider to be good enough to be used * without checking any other formats. * Default value is {@link MatchStrength#SOLID_MATCH}, */ protected final MatchStrength _optimalMatch; /** * Strength of minimal match we accept as the answer, unless * better matches are found. * Default value is {@link MatchStrength#WEAK_MATCH}, */ protected final MatchStrength _minimalMatch; /** * Maximum number of leading bytes of the input that we can read * to determine data format. *

* Default value is {@link #DEFAULT_MAX_INPUT_LOOKAHEAD}. */ protected final int _maxInputLookahead; /* /********************************************************** /* Construction /********************************************************** */ public DataFormatDetector(JsonFactory... detectors) { this(detectors, MatchStrength.SOLID_MATCH, MatchStrength.WEAK_MATCH, DEFAULT_MAX_INPUT_LOOKAHEAD); } public DataFormatDetector(Collection detectors) { this(detectors.toArray(new JsonFactory[detectors.size()])); } /** * Method that will return a detector instance that uses given * optimal match level (match that is considered sufficient to return, without * trying to find stronger matches with other formats). */ public DataFormatDetector withOptimalMatch(MatchStrength optMatch) { if (optMatch == _optimalMatch) { return this; } return new DataFormatDetector(_detectors, optMatch, _minimalMatch, _maxInputLookahead); } /** * Method that will return a detector instance that uses given * minimal match level; match that may be returned unless a stronger match * is found with other format detectors. */ public DataFormatDetector withMinimalMatch(MatchStrength minMatch) { if (minMatch == _minimalMatch) { return this; } return new DataFormatDetector(_detectors, _optimalMatch, minMatch, _maxInputLookahead); } /** * Method that will return a detector instance that allows detectors to * read up to specified number of bytes when determining format match strength. */ public DataFormatDetector withMaxInputLookahead(int lookaheadBytes) { if (lookaheadBytes == _maxInputLookahead) { return this; } return new DataFormatDetector(_detectors, _optimalMatch, _minimalMatch, lookaheadBytes); } private DataFormatDetector(JsonFactory[] detectors, MatchStrength optMatch, MatchStrength minMatch, int maxInputLookahead) { _detectors = detectors; _optimalMatch = optMatch; _minimalMatch = minMatch; _maxInputLookahead = maxInputLookahead; } /* /********************************************************** /* Public API /********************************************************** */ /** * Method to call to find format that content (accessible via given * {@link InputStream}) given has, as per configuration of this detector * instance. * * @return Matcher object which contains result; never null, even in cases * where no match (with specified minimal match strength) is found. */ public DataFormatMatcher findFormat(InputStream in) throws IOException { return _findFormat(new InputAccessor.Std(in, new byte[_maxInputLookahead])); } /** * Method to call to find format that given content (full document) * has, as per configuration of this detector instance. * * @return Matcher object which contains result; never null, even in cases * where no match (with specified minimal match strength) is found. */ public DataFormatMatcher findFormat(byte[] fullInputData) throws IOException { return _findFormat(new InputAccessor.Std(fullInputData)); } /* /********************************************************** /* Internal methods /********************************************************** */ private DataFormatMatcher _findFormat(InputAccessor.Std acc) throws IOException { JsonFactory bestMatch = null; MatchStrength bestMatchStrength = null; for (JsonFactory f : _detectors) { acc.reset(); MatchStrength strength = f.hasFormat(acc); // if not better than what we have so far (including minimal level limit), skip if (strength == null || strength.ordinal() < _minimalMatch.ordinal()) { continue; } // also, needs to better match than before if (bestMatch != null) { if (bestMatchStrength.ordinal() >= strength.ordinal()) { continue; } } // finally: if it's good enough match, we are done bestMatch = f; bestMatchStrength = strength; if (strength.ordinal() >= _optimalMatch.ordinal()) { break; } } return acc.createMatcher(bestMatch, bestMatchStrength); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/format/package-info.java0000644000175000017500000000035311655120726026621 0ustar jamespagejamespage/** * Package that contains interfaces needed for dynamic, pluggable * format (auto)detection; as well as basic utility classes for * simple format detection functionality. * * @since 1.8 */ package org.codehaus.jackson.format; jackson-src-1.9.2/src/java/org/codehaus/jackson/format/DataFormatMatcher.java0000644000175000017500000000703411655120726027626 0ustar jamespagejamespagepackage org.codehaus.jackson.format; import java.io.*; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.io.MergedStream; /** * Result object constructed by {@link DataFormatDetector} when requested * to detect format of given input data. */ public class DataFormatMatcher { protected final InputStream _originalStream; /** * Content read during format matching process */ protected final byte[] _bufferedData; /** * Number of bytes in {@link #_bufferedData} that were read. */ protected final int _bufferedLength; /** * Factory that produced sufficient match (if any) */ protected final JsonFactory _match; /** * Strength of match with {@link #_match} */ protected final MatchStrength _matchStrength; protected DataFormatMatcher(InputStream in, byte[] buffered, int bufferedLength, JsonFactory match, MatchStrength strength) { _originalStream = in; _bufferedData = buffered; _bufferedLength = bufferedLength; _match = match; _matchStrength = strength; } /* /********************************************************** /* Public API, simple accessors /********************************************************** */ /** * Accessor to use to see if any formats matched well enough with * the input data. */ public boolean hasMatch() { return _match != null; } /** * Method for accessing strength of the match, if any; if no match, * will return {@link MatchStrength#INCONCLUSIVE}. */ public MatchStrength getMatchStrength() { return (_matchStrength == null) ? MatchStrength.INCONCLUSIVE : _matchStrength; } /** * Accessor for {@link JsonFactory} that represents format that data matched. */ public JsonFactory getMatch() { return _match; } /** * Accessor for getting brief textual name of matched format if any (null * if none). Equivalent to: *

     *   return hasMatch() ? getMatch().getFormatName() : null;
     *
*/ public String getMatchedFormatName() { return _match.getFormatName(); } /* /********************************************************** /* Public API, factory methods /********************************************************** */ /** * Convenience method for trying to construct a {@link JsonParser} for * parsing content which is assumed to be in detected data format. * If no match was found, returns null. */ public JsonParser createParserWithMatch() throws IOException { if (_match == null) { return null; } if (_originalStream == null) { return _match.createJsonParser(_bufferedData, 0, _bufferedLength); } return _match.createJsonParser(getDataStream()); } /** * Method to use for accessing input for which format detection has been done. * This must be used instead of using stream passed to detector * unless given stream itself can do buffering. * Stream will return all content that was read during matching process, as well * as remaining contents of the underlying stream. */ public InputStream getDataStream() { if (_originalStream == null) { return new ByteArrayInputStream(_bufferedData, 0, _bufferedLength); } return new MergedStream(null, _originalStream, _bufferedData, 0, _bufferedLength); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/format/InputAccessor.java0000644000175000017500000000715611655120726027067 0ustar jamespagejamespagepackage org.codehaus.jackson.format; import java.io.*; import org.codehaus.jackson.JsonFactory; /** * Interface used to expose beginning of a data file to data format * detection code. * * @since 1.8 */ public interface InputAccessor { /** * Method to call to check if more input is available. * Since this may result in more content to be read (at least * one more byte), a {@link IOException} may get thrown. */ public boolean hasMoreBytes() throws IOException; /** * Returns next byte available, if any; if no more bytes are * available, will throw {@link java.io.EOFException}. */ public byte nextByte() throws IOException; /** * Method that can be called to reset accessor to read from beginning * of input. */ public void reset(); /* /********************************************************** /* Standard implementation /********************************************************** */ /** * Basic implementation that reads data from given * {@link InputStream} and buffers it as necessary. */ public class Std implements InputAccessor { protected final InputStream _in; protected final byte[] _buffer; /** * Number of bytes in {@link #_buffer} that are valid * buffered content. */ protected int _bufferedAmount; /** * Pointer to next available buffered byte in {@link #_buffer}. */ protected int _ptr; /** * Constructor used when content to check is available via * input stream and must be read. */ public Std(InputStream in, byte[] buffer) { _in = in; _buffer = buffer; _bufferedAmount = 0; } /** * Constructor used when the full input (or at least enough leading bytes * of full input) is available. */ public Std(byte[] inputDocument) { _in = null; _buffer = inputDocument; // we have it all: _bufferedAmount = inputDocument.length; } @Override public boolean hasMoreBytes() throws IOException { if (_ptr < _bufferedAmount) { // already got more return true; } int amount = _buffer.length - _ptr; if (amount < 1) { // can not load any more return false; } int count = _in.read(_buffer, _ptr, amount); if (count <= 0) { // EOF return false; } _bufferedAmount += count; return true; } @Override public byte nextByte() throws IOException { // should we just try loading more automatically? if (_ptr >- _bufferedAmount) { if (!hasMoreBytes()) { throw new EOFException("Could not read more than "+_ptr+" bytes (max buffer size: "+_buffer.length+")"); } } return _buffer[_ptr++]; } @Override public void reset() { _ptr = 0; } /* /********************************************************** /* Extended API for DataFormatDetector/Matcher /********************************************************** */ public DataFormatMatcher createMatcher(JsonFactory match, MatchStrength matchStrength) { return new DataFormatMatcher(_in, _buffer, _bufferedAmount, match, matchStrength); } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/format/MatchStrength.java0000644000175000017500000000504211655120726027050 0ustar jamespagejamespagepackage org.codehaus.jackson.format; /** * Enumeration used to indicate strength of match between data format * and piece of data (typically beginning of a data file). * Values are in increasing match strength; and detectors should return * "strongest" value: that is, it should start with strongest match * criteria, and downgrading if criteria is not fulfilled. * * @since 1.8 */ public enum MatchStrength { /** * Value that indicates that given data can not be in given format. */ NO_MATCH, /** * Value that indicates that detector can not find out whether could * be a match or not. * This can occur for example for textual data formats t * when there are so many leading spaces that detector can not * find the first data byte (because detectors typically limit lookahead * to some smallish value). */ INCONCLUSIVE, /** * Value that indicates that given data could be of specified format (i.e. * it can not be ruled out). This can occur for example when seen data * is both not in canonical formats (for example: JSON data should be a JSON Array or Object * not a scalar value, as per JSON specification) and there are known use case * where a format detected is actually used (plain JSON Strings are actually used, even * though specification does not indicate that as valid usage: as such, seeing a leading * double-quote could indicate a JSON String, which plausibly could indicate * non-standard JSON usage). */ WEAK_MATCH, /** * Value that indicates that given data conforms to (one of) canonical form(s) of * the data format. *

* For example, when testing for XML data format, * seeing a less-than character ("<") alone (with possible leading spaces) * would be a strong indication that data could * be in xml format (but see below for {@link #FULL_MATCH} description for more) */ SOLID_MATCH, /** * Value that indicates that given data contains a signature that is deemed * specific enough to uniquely indicate data format used. *

* For example, when testing for XML data format, * seing "<xml" as the first data bytes ("XML declaration", as per XML specification) * could give full confidence that data is indeed in XML format. * Not all data formats have unique leading identifiers to allow full matches; for example, * JSON only has heuristic matches and can have at most {@link #SOLID_MATCH}) match. */ FULL_MATCH ; } jackson-src-1.9.2/src/java/org/codehaus/jackson/SerializableString.java0000644000175000017500000000303611655120726026603 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Interface that defines how Jackson package can interact with efficient * pre-serialized or lazily-serialized and reused String representations. * Typically implementations store possible serialized version(s) so that * serialization of String can be done more efficiently, especially when * used multiple times. * * @since 1.7 (1.6 introduced implementation, but interface extracted later) * * @see org.codehaus.jackson.io.SerializedString */ public interface SerializableString { /** * Returns unquoted String that this object represents (and offers * serialized forms for) */ public String getValue(); /** * Returns length of the (unquoted) String as characters. * Functionally equvalent to: *

     *   getValue().length();
     *
*/ public int charLength(); /** * Returns JSON quoted form of the String, as character array. Result * can be embedded as-is in textual JSON as property name or JSON String. */ public char[] asQuotedChars(); /** * Returns UTF-8 encoded version of unquoted String. * Functionally equivalent to (but more efficient than): *
     * getValue().getBytes("UTF-8");
     *
*/ public byte[] asUnquotedUTF8(); /** * Returns UTF-8 encoded version of JSON-quoted String. * Functionally equivalent to (but more efficient than): *
     * new String(asQuotedChars()).getBytes("UTF-8");
     *
*/ public byte[] asQuotedUTF8(); } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/0000755000175000017500000000000011672662540022554 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/io/InputDecorator.java0000644000175000017500000000555711655120726026371 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import java.io.*; /** * Handler class that can be used to decorate input sources. * Typical use is to use a filter abstraction (filtered stream, * reader) around original input source, and apply additional * processing during read operations. * * @since 1.8 */ public abstract class InputDecorator { /** * Method called by {@link org.codehaus.jackson.JsonFactory} instance when * creating parser given an {@link InputStream}, when this decorator * has been registered. * * @param ctxt IO context in use (provides access to declared encoding). * NOTE: at this point context may not have all information initialized; * specifically auto-detected encoding is only available once parsing starts, * which may occur only after this method is called. * @param in Original input source * * @return InputStream to use; either passed in argument, or something that * calls it */ public abstract InputStream decorate(IOContext ctxt, InputStream in) throws IOException; /** * Method called by {@link org.codehaus.jackson.JsonFactory} instance when * creating parser on given "raw" byte source. * Method can either construct a {@link InputStream} for reading; or return * null to indicate that no wrapping should occur. * * @param ctxt IO context in use (provides access to declared encoding) * NOTE: at this point context may not have all information initialized; * specifically auto-detected encoding is only available once parsing starts, * which may occur only after this method is called. * @param src Input buffer that contains contents to parse * @param offset Offset of the first available byte in the input buffer * @param length Number of bytes available in the input buffer * * @return Either {@link InputStream} to use as input source; or null to indicate * that contents are to be processed as-is by caller */ public abstract InputStream decorate(IOContext ctxt, byte[] src, int offset, int length) throws IOException; /** * Method called by {@link org.codehaus.jackson.JsonFactory} instance when * creating parser given an {@link Reader}, when this decorator * has been registered. * * @param ctxt IO context in use (provides access to declared encoding) * NOTE: at this point context may not have all information initialized; * specifically auto-detected encoding is only available once parsing starts, * which may occur only after this method is called. * @param src Original input source * * @return Reader to use; either passed in argument, or something that * calls it (for example, a {@link FilterReader}) */ public abstract Reader decorate(IOContext ctxt, Reader src) throws IOException; } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/BaseReader.java0000644000175000017500000000563111655120726025415 0ustar jamespagejamespage package org.codehaus.jackson.io; import java.io.*; /** * Simple basic class for optimized readers in this package; implements * "cookie-cutter" methods that are used by all actual implementations. */ abstract class BaseReader extends Reader { /** * JSON actually limits available Unicode range in the high end * to the same as xml (to basically limit UTF-8 max byte sequence * length to 4) */ final protected static int LAST_VALID_UNICODE_CHAR = 0x10FFFF; final protected static char NULL_CHAR = (char) 0; final protected static char NULL_BYTE = (byte) 0; final protected IOContext _context; protected InputStream _in; protected byte[] _buffer; protected int _ptr; protected int _length; /* /********************************************************** /* Life-cycle /********************************************************** */ protected BaseReader(IOContext context, InputStream in, byte[] buf, int ptr, int len) { _context = context; _in = in; _buffer = buf; _ptr = ptr; _length = len; } /* /********************************************************** /* Reader API /********************************************************** */ @Override public void close() throws IOException { InputStream in = _in; if (in != null) { _in = null; freeBuffers(); in.close(); } } protected char[] _tmpBuf = null; /** * Although this method is implemented by the base class, AND it should * never be called by main code, let's still implement it bit more * efficiently just in case */ @Override public int read() throws IOException { if (_tmpBuf == null) { _tmpBuf = new char[1]; } if (read(_tmpBuf, 0, 1) < 1) { return -1; } return _tmpBuf[0]; } /* /********************************************************** /* Internal/package methods: /********************************************************** */ /** * This method should be called along with (or instead of) normal * close. After calling this method, no further reads should be tried. * Method will try to recycle read buffers (if any). */ public final void freeBuffers() { byte[] buf = _buffer; if (buf != null) { _buffer = null; _context.releaseReadIOBuffer(buf); } } protected void reportBounds(char[] cbuf, int start, int len) throws IOException { throw new ArrayIndexOutOfBoundsException("read(buf,"+start+","+len+"), cbuf["+cbuf.length+"]"); } protected void reportStrangeStream() throws IOException { throw new IOException("Strange I/O stream, returned 0 bytes on read"); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/UTF32Reader.java0000644000175000017500000001472511655120726025352 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import java.io.*; /** * Since JDK does not come with UTF-32/UCS-4, let's implement a simple * decoder to use. */ public final class UTF32Reader extends BaseReader { final boolean mBigEndian; /** * Although input is fine with full Unicode set, Java still uses * 16-bit chars, so we may have to split high-order chars into * surrogate pairs. */ char mSurrogate = NULL_CHAR; /** * Total read character count; used for error reporting purposes */ int mCharCount = 0; /** * Total read byte count; used for error reporting purposes */ int mByteCount = 0; /* //////////////////////////////////////// // Life-cycle //////////////////////////////////////// */ public UTF32Reader(IOContext ctxt, InputStream in, byte[] buf, int ptr, int len, boolean isBigEndian) { super(ctxt, in, buf, ptr, len); mBigEndian = isBigEndian; } /* //////////////////////////////////////// // Public API //////////////////////////////////////// */ @Override public int read(char[] cbuf, int start, int len) throws IOException { // Already EOF? if (_buffer == null) { return -1; } if (len < 1) { return len; } // Let's then ensure there's enough room... if (start < 0 || (start+len) > cbuf.length) { reportBounds(cbuf, start, len); } len += start; int outPtr = start; // Ok, first; do we have a surrogate from last round? if (mSurrogate != NULL_CHAR) { cbuf[outPtr++] = mSurrogate; mSurrogate = NULL_CHAR; // No need to load more, already got one char } else { /* Note: we'll try to avoid blocking as much as possible. As a * result, we only need to get 4 bytes for a full char. */ int left = (_length - _ptr); if (left < 4) { if (!loadMore(left)) { // (legal) EOF? return -1; } } } main_loop: while (outPtr < len) { int ptr = _ptr; int ch; if (mBigEndian) { ch = (_buffer[ptr] << 24) | ((_buffer[ptr+1] & 0xFF) << 16) | ((_buffer[ptr+2] & 0xFF) << 8) | (_buffer[ptr+3] & 0xFF); } else { ch = (_buffer[ptr] & 0xFF) | ((_buffer[ptr+1] & 0xFF) << 8) | ((_buffer[ptr+2] & 0xFF) << 16) | (_buffer[ptr+3] << 24); } _ptr += 4; // Does it need to be split to surrogates? // (also, we can and need to verify illegal chars) if (ch > 0xFFFF) { // need to split into surrogates? if (ch > LAST_VALID_UNICODE_CHAR) { reportInvalid(ch, outPtr-start, "(above "+Integer.toHexString(LAST_VALID_UNICODE_CHAR)+") "); } ch -= 0x10000; // to normalize it starting with 0x0 cbuf[outPtr++] = (char) (0xD800 + (ch >> 10)); // hmmh. can this ever be 0? (not legal, at least?) ch = (0xDC00 | (ch & 0x03FF)); // Room for second part? if (outPtr >= len) { // nope mSurrogate = (char) ch; break main_loop; } } cbuf[outPtr++] = (char) ch; if (_ptr >= _length) { break main_loop; } } len = outPtr - start; mCharCount += len; return len; } /* //////////////////////////////////////// // Internal methods //////////////////////////////////////// */ private void reportUnexpectedEOF(int gotBytes, int needed) throws IOException { int bytePos = mByteCount + gotBytes; int charPos = mCharCount; throw new CharConversionException("Unexpected EOF in the middle of a 4-byte UTF-32 char: got " +gotBytes+", needed "+needed +", at char #"+charPos+", byte #"+bytePos+")"); } private void reportInvalid(int value, int offset, String msg) throws IOException { int bytePos = mByteCount + _ptr - 1; int charPos = mCharCount + offset; throw new CharConversionException("Invalid UTF-32 character 0x" +Integer.toHexString(value) +msg+" at char #"+charPos+", byte #"+bytePos+")"); } /** * @param available Number of "unused" bytes in the input buffer * * @return True, if enough bytes were read to allow decoding of at least * one full character; false if EOF was encountered instead. */ private boolean loadMore(int available) throws IOException { mByteCount += (_length - available); // Bytes that need to be moved to the beginning of buffer? if (available > 0) { if (_ptr > 0) { for (int i = 0; i < available; ++i) { _buffer[i] = _buffer[_ptr+i]; } _ptr = 0; } _length = available; } else { /* Ok; here we can actually reasonably expect an EOF, * so let's do a separate read right away: */ _ptr = 0; int count = _in.read(_buffer); if (count < 1) { _length = 0; if (count < 0) { // -1 freeBuffers(); // to help GC? return false; } // 0 count is no good; let's err out reportStrangeStream(); } _length = count; } /* Need at least 4 bytes; if we don't get that many, it's an * error. */ while (_length < 4) { int count = _in.read(_buffer, _length, _buffer.length - _length); if (count < 1) { if (count < 0) { // -1, EOF... no good! freeBuffers(); // to help GC? reportUnexpectedEOF(_length, 4); } // 0 count is no good; let's err out reportStrangeStream(); } _length += count; } return true; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/NumberInput.java0000644000175000017500000002362511655120726025673 0ustar jamespagejamespagepackage org.codehaus.jackson.io; public final class NumberInput { /** * Textual representation of a double constant that can cause nasty problems * with JDK (see http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308). */ public final static String NASTY_SMALL_DOUBLE = "2.2250738585072012e-308"; /** * Constants needed for parsing longs from basic int parsing methods */ final static long L_BILLION = 1000000000; final static String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE).substring(1); final static String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE); /** * Fast method for parsing integers that are known to fit into * regular 32-bit signed int type. This means that length is * between 1 and 9 digits (inclusive) *

* Note: public to let unit tests call it */ public final static int parseInt(char[] digitChars, int offset, int len) { int num = digitChars[offset] - '0'; len += offset; // This looks ugly, but appears the fastest way (as per measurements) if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); if (++offset < len) { num = (num * 10) + (digitChars[offset] - '0'); } } } } } } } } return num; } /** * Helper method to (more) efficiently parse integer numbers from * String values. * * @since 1.7 */ public final static int parseInt(String str) { /* Ok: let's keep strategy simple: ignoring optional minus sign, * we'll accept 1 - 9 digits and parse things efficiently; * otherwise just defer to JDK parse functionality. */ char c = str.charAt(0); int length = str.length(); boolean negative = (c == '-'); int offset = 1; // must have 1 - 9 digits after optional sign: // negative? if (negative) { if (length == 1 || length > 10) { return Integer.parseInt(str); } c = str.charAt(offset++); } else { if (length > 9) { return Integer.parseInt(str); } } if (c > '9' || c < '0') { return Integer.parseInt(str); } int num = c - '0'; if (offset < length) { c = str.charAt(offset++); if (c > '9' || c < '0') { return Integer.parseInt(str); } num = (num * 10) + (c - '0'); if (offset < length) { c = str.charAt(offset++); if (c > '9' || c < '0') { return Integer.parseInt(str); } num = (num * 10) + (c - '0'); // Let's just loop if we have more than 3 digits: if (offset < length) { do { c = str.charAt(offset++); if (c > '9' || c < '0') { return Integer.parseInt(str); } num = (num * 10) + (c - '0'); } while (offset < length); } } } return negative ? -num : num; } public final static long parseLong(char[] digitChars, int offset, int len) { // Note: caller must ensure length is [10, 18] int len1 = len-9; long val = parseInt(digitChars, offset, len1) * L_BILLION; return val + (long) parseInt(digitChars, offset+len1, 9); } public final static long parseLong(String str) { /* Ok, now; as the very first thing, let's just optimize case of "fake longs"; * that is, if we know they must be ints, call int parsing */ int length = str.length(); if (length <= 9) { return (long) parseInt(str); } // !!! TODO: implement efficient 2-int parsing... return Long.parseLong(str); } /** * Helper method for determining if given String representation of * an integral number would fit in 64-bit Java long or not. * Note that input String must NOT contain leading minus sign (even * if 'negative' is set to true). * * @param negative Whether original number had a minus sign (which is * NOT passed to this method) or not */ public final static boolean inLongRange(char[] digitChars, int offset, int len, boolean negative) { String cmpStr = negative ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR; int cmpLen = cmpStr.length(); if (len < cmpLen) return true; if (len > cmpLen) return false; for (int i = 0; i < cmpLen; ++i) { int diff = digitChars[offset+i] - cmpStr.charAt(i); if (diff != 0) { return (diff < 0); } } return true; } /** * Similar to {@link #inLongRange(char[],int,int,boolean)}, but * with String argument * * @param negative Whether original number had a minus sign (which is * NOT passed to this method) or not * * @since 1.5.0 */ public final static boolean inLongRange(String numberStr, boolean negative) { String cmpStr = negative ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR; int cmpLen = cmpStr.length(); int actualLen = numberStr.length(); if (actualLen < cmpLen) return true; if (actualLen > cmpLen) return false; // could perhaps just use String.compareTo()? for (int i = 0; i < cmpLen; ++i) { int diff = numberStr.charAt(i) - cmpStr.charAt(i); if (diff != 0) { return (diff < 0); } } return true; } /** * @since 1.6 */ public static int parseAsInt(String input, int defaultValue) { if (input == null) { return defaultValue; } input = input.trim(); int len = input.length(); if (len == 0) { return defaultValue; } // One more thing: use integer parsing for 'simple' int i = 0; if (i < len) { // skip leading sign: char c = input.charAt(0); if (c == '+') { // for plus, actually physically remove input = input.substring(1); len = input.length(); } else if (c == '-') { // minus, just skip for checks, must retain ++i; } } for (; i < len; ++i) { char c = input.charAt(i); // if other symbols, parse as Double, coerce if (c > '9' || c < '0') { try { return (int) parseDouble(input); } catch (NumberFormatException e) { return defaultValue; } } } try { return Integer.parseInt(input); } catch (NumberFormatException e) { } return defaultValue; } /** * @since 1.6 */ public static long parseAsLong(String input, long defaultValue) { if (input == null) { return defaultValue; } input = input.trim(); int len = input.length(); if (len == 0) { return defaultValue; } // One more thing: use long parsing for 'simple' int i = 0; if (i < len) { // skip leading sign: char c = input.charAt(0); if (c == '+') { // for plus, actually physically remove input = input.substring(1); len = input.length(); } else if (c == '-') { // minus, just skip for checks, must retain ++i; } } for (; i < len; ++i) { char c = input.charAt(i); // if other symbols, parse as Double, coerce if (c > '9' || c < '0') { try { return (long) parseDouble(input); } catch (NumberFormatException e) { return defaultValue; } } } try { return Long.parseLong(input); } catch (NumberFormatException e) { } return defaultValue; } /** * @since 1.6 */ public static double parseAsDouble(String input, double defaultValue) { if (input == null) { return defaultValue; } input = input.trim(); int len = input.length(); if (len == 0) { return defaultValue; } try { return parseDouble(input); } catch (NumberFormatException e) { } return defaultValue; } /** * @since 1.8 */ public final static double parseDouble(String numStr) throws NumberFormatException { // [JACKSON-486]: avoid some nasty float representations... but should it be MIN_NORMAL or MIN_VALUE? if (NASTY_SMALL_DOUBLE.equals(numStr)) { return Double.MIN_NORMAL; } return Double.parseDouble(numStr); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/NumberOutput.java0000644000175000017500000003223011655120726026064 0ustar jamespagejamespagepackage org.codehaus.jackson.io; public final class NumberOutput { private final static char NULL_CHAR = (char) 0; private static int MILLION = 1000000; private static int BILLION = 1000000000; private static long TEN_BILLION_L = 10000000000L; private static long THOUSAND_L = 1000L; private static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE; private static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE; final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE); final static char[] LEADING_TRIPLETS = new char[4000]; final static char[] FULL_TRIPLETS = new char[4000]; static { /* Let's fill it with NULLs for ignorable leading digits, * and digit chars for others */ int ix = 0; for (int i1 = 0; i1 < 10; ++i1) { char f1 = (char) ('0' + i1); char l1 = (i1 == 0) ? NULL_CHAR : f1; for (int i2 = 0; i2 < 10; ++i2) { char f2 = (char) ('0' + i2); char l2 = (i1 == 0 && i2 == 0) ? NULL_CHAR : f2; for (int i3 = 0; i3 < 10; ++i3) { // Last is never to be empty char f3 = (char) ('0' + i3); LEADING_TRIPLETS[ix] = l1; LEADING_TRIPLETS[ix+1] = l2; LEADING_TRIPLETS[ix+2] = f3; FULL_TRIPLETS[ix] = f1; FULL_TRIPLETS[ix+1] = f2; FULL_TRIPLETS[ix+2] = f3; ix += 4; } } } } final static byte[] FULL_TRIPLETS_B = new byte[4000]; static { for (int i = 0; i < 4000; ++i) { FULL_TRIPLETS_B[i] = (byte) FULL_TRIPLETS[i]; } } final static String[] sSmallIntStrs = new String[] { "0","1","2","3","4","5","6","7","8","9","10" }; final static String[] sSmallIntStrs2 = new String[] { "-1","-2","-3","-4","-5","-6","-7","-8","-9","-10" }; /* /********************************************************** /* Efficient serialization methods using raw buffers /********************************************************** */ /** * @return Offset within buffer after outputting int */ public static int outputInt(int value, char[] buffer, int offset) { if (value < 0) { if (value == Integer.MIN_VALUE) { /* Special case: no matching positive value within range; * let's then "upgrade" to long and output as such. */ return outputLong((long) value, buffer, offset); } buffer[offset++] = '-'; value = -value; } if (value < MILLION) { // at most 2 triplets... if (value < 1000) { if (value < 10) { buffer[offset++] = (char) ('0' + value); } else { offset = outputLeadingTriplet(value, buffer, offset); } } else { int thousands = value / 1000; value -= (thousands * 1000); // == value % 1000 offset = outputLeadingTriplet(thousands, buffer, offset); offset = outputFullTriplet(value, buffer, offset); } return offset; } // ok, all 3 triplets included /* Let's first hand possible billions separately before * handling 3 triplets. This is possible since we know we * can have at most '2' as billion count. */ boolean hasBillions = (value >= BILLION); if (hasBillions) { value -= BILLION; if (value >= BILLION) { value -= BILLION; buffer[offset++] = '2'; } else { buffer[offset++] = '1'; } } int newValue = value / 1000; int ones = (value - (newValue * 1000)); // == value % 1000 value = newValue; newValue /= 1000; int thousands = (value - (newValue * 1000)); // value now has millions, which have 1, 2 or 3 digits if (hasBillions) { offset = outputFullTriplet(newValue, buffer, offset); } else { offset = outputLeadingTriplet(newValue, buffer, offset); } offset = outputFullTriplet(thousands, buffer, offset); offset = outputFullTriplet(ones, buffer, offset); return offset; } public static int outputInt(int value, byte[] buffer, int offset) { if (value < 0) { if (value == Integer.MIN_VALUE) { return outputLong((long) value, buffer, offset); } buffer[offset++] = '-'; value = -value; } if (value < MILLION) { // at most 2 triplets... if (value < 1000) { if (value < 10) { buffer[offset++] = (byte) ('0' + value); } else { offset = outputLeadingTriplet(value, buffer, offset); } } else { int thousands = value / 1000; value -= (thousands * 1000); // == value % 1000 offset = outputLeadingTriplet(thousands, buffer, offset); offset = outputFullTriplet(value, buffer, offset); } return offset; } boolean hasBillions = (value >= BILLION); if (hasBillions) { value -= BILLION; if (value >= BILLION) { value -= BILLION; buffer[offset++] = '2'; } else { buffer[offset++] = '1'; } } int newValue = value / 1000; int ones = (value - (newValue * 1000)); // == value % 1000 value = newValue; newValue /= 1000; int thousands = (value - (newValue * 1000)); if (hasBillions) { offset = outputFullTriplet(newValue, buffer, offset); } else { offset = outputLeadingTriplet(newValue, buffer, offset); } offset = outputFullTriplet(thousands, buffer, offset); offset = outputFullTriplet(ones, buffer, offset); return offset; } /** * @return Offset within buffer after outputting int */ public static int outputLong(long value, char[] buffer, int offset) { // First: does it actually fit in an int? if (value < 0L) { /* MIN_INT is actually printed as long, just because its * negation is not an int but long */ if (value > MIN_INT_AS_LONG) { return outputInt((int) value, buffer, offset); } if (value == Long.MIN_VALUE) { // Special case: no matching positive value within range int len = SMALLEST_LONG.length(); SMALLEST_LONG.getChars(0, len, buffer, offset); return (offset + len); } buffer[offset++] = '-'; value = -value; } else { if (value <= MAX_INT_AS_LONG) { return outputInt((int) value, buffer, offset); } } /* Ok: real long print. Need to first figure out length * in characters, and then print in from end to beginning */ int origOffset = offset; offset += calcLongStrLength(value); int ptr = offset; // First, with long arithmetics: while (value > MAX_INT_AS_LONG) { // full triplet ptr -= 3; long newValue = value / THOUSAND_L; int triplet = (int) (value - newValue * THOUSAND_L); outputFullTriplet(triplet, buffer, ptr); value = newValue; } // Then with int arithmetics: int ivalue = (int) value; while (ivalue >= 1000) { // still full triplet ptr -= 3; int newValue = ivalue / 1000; int triplet = ivalue - (newValue * 1000); outputFullTriplet(triplet, buffer, ptr); ivalue = newValue; } // And finally, if anything remains, partial triplet outputLeadingTriplet(ivalue, buffer, origOffset); return offset; } public static int outputLong(long value, byte[] buffer, int offset) { if (value < 0L) { if (value > MIN_INT_AS_LONG) { return outputInt((int) value, buffer, offset); } if (value == Long.MIN_VALUE) { // Special case: no matching positive value within range int len = SMALLEST_LONG.length(); for (int i = 0; i < len; ++i) { buffer[offset++] = (byte) SMALLEST_LONG.charAt(i); } return offset; } buffer[offset++] = '-'; value = -value; } else { if (value <= MAX_INT_AS_LONG) { return outputInt((int) value, buffer, offset); } } int origOffset = offset; offset += calcLongStrLength(value); int ptr = offset; // First, with long arithmetics: while (value > MAX_INT_AS_LONG) { // full triplet ptr -= 3; long newValue = value / THOUSAND_L; int triplet = (int) (value - newValue * THOUSAND_L); outputFullTriplet(triplet, buffer, ptr); value = newValue; } // Then with int arithmetics: int ivalue = (int) value; while (ivalue >= 1000) { // still full triplet ptr -= 3; int newValue = ivalue / 1000; int triplet = ivalue - (newValue * 1000); outputFullTriplet(triplet, buffer, ptr); ivalue = newValue; } outputLeadingTriplet(ivalue, buffer, origOffset); return offset; } /* /********************************************************** /* Secondary convenience serialization methods /********************************************************** */ /* !!! 05-Aug-2008, tatus: Any ways to further optimize * these? (or need: only called by diagnostics methods?) */ public static String toString(int value) { // Lookup table for small values if (value < sSmallIntStrs.length) { if (value >= 0) { return sSmallIntStrs[value]; } int v2 = -value - 1; if (v2 < sSmallIntStrs2.length) { return sSmallIntStrs2[v2]; } } return Integer.toString(value); } public static String toString(long value) { if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE) { return toString((int) value); } return Long.toString(value); } public static String toString(double value) { return Double.toString(value); } /* /********************************************************** /* Internal methods /********************************************************** */ private static int outputLeadingTriplet(int triplet, char[] buffer, int offset) { int digitOffset = (triplet << 2); char c = LEADING_TRIPLETS[digitOffset++]; if (c != NULL_CHAR) { buffer[offset++] = c; } c = LEADING_TRIPLETS[digitOffset++]; if (c != NULL_CHAR) { buffer[offset++] = c; } // Last is required to be non-empty buffer[offset++] = LEADING_TRIPLETS[digitOffset]; return offset; } private static int outputLeadingTriplet(int triplet, byte[] buffer, int offset) { int digitOffset = (triplet << 2); char c = LEADING_TRIPLETS[digitOffset++]; if (c != NULL_CHAR) { buffer[offset++] = (byte) c; } c = LEADING_TRIPLETS[digitOffset++]; if (c != NULL_CHAR) { buffer[offset++] = (byte) c; } // Last is required to be non-empty buffer[offset++] = (byte) LEADING_TRIPLETS[digitOffset]; return offset; } private static int outputFullTriplet(int triplet, char[] buffer, int offset) { int digitOffset = (triplet << 2); buffer[offset++] = FULL_TRIPLETS[digitOffset++]; buffer[offset++] = FULL_TRIPLETS[digitOffset++]; buffer[offset++] = FULL_TRIPLETS[digitOffset]; return offset; } private static int outputFullTriplet(int triplet, byte[] buffer, int offset) { int digitOffset = (triplet << 2); buffer[offset++] = FULL_TRIPLETS_B[digitOffset++]; buffer[offset++] = FULL_TRIPLETS_B[digitOffset++]; buffer[offset++] = FULL_TRIPLETS_B[digitOffset]; return offset; } /** *

* Pre-conditions: posValue is positive, and larger than * Integer.MAX_VALUE (about 2 billions). */ private static int calcLongStrLength(long posValue) { int len = 10; long comp = TEN_BILLION_L; // 19 is longest, need to worry about overflow while (posValue >= comp) { if (len == 19) { break; } ++len; comp = (comp << 3) + (comp << 1); // 10x } return len; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/JsonStringEncoder.java0000644000175000017500000003760611655120726027027 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import java.lang.ref.SoftReference; import org.codehaus.jackson.util.BufferRecycler; import org.codehaus.jackson.util.ByteArrayBuilder; import org.codehaus.jackson.util.CharTypes; import org.codehaus.jackson.util.TextBuffer; /** * Helper class used for efficient encoding of JSON String values (including * JSON field names) into Strings or UTF-8 byte arrays. *

* Note that methods in here are somewhat optimized, but not ridiculously so. * Reason is that conversion method results are expected to be cached so that * these methods will not be hot spots during normal operation. * * @since 1.6 */ public final class JsonStringEncoder { private final static char[] HEX_CHARS = CharTypes.copyHexChars(); private final static byte[] HEX_BYTES = CharTypes.copyHexBytes(); private final static int SURR1_FIRST = 0xD800; private final static int SURR1_LAST = 0xDBFF; private final static int SURR2_FIRST = 0xDC00; private final static int SURR2_LAST = 0xDFFF; private final static int INT_BACKSLASH = '\\'; private final static int INT_U = 'u'; private final static int INT_0 = '0'; /** * This ThreadLocal contains a {@link java.lang.ref.SoftRerefence} * to a {@link BufferRecycler} used to provide a low-cost * buffer recycling between reader and writer instances. */ final protected static ThreadLocal> _threadEncoder = new ThreadLocal>(); /** * Lazily constructed text buffer used to produce JSON encoded Strings * as characters (without UTF-8 encoding) */ protected TextBuffer _textBuffer; /** * Lazily-constructed builder used for UTF-8 encoding of text values * (quoted and unquoted) */ protected ByteArrayBuilder _byteBuilder; /** * Temporary buffer used for composing quote/escape sequences */ protected final char[] _quoteBuffer; /* /********************************************************** /* Construction, instance access /********************************************************** */ public JsonStringEncoder() { _quoteBuffer = new char[6]; _quoteBuffer[0] = '\\'; _quoteBuffer[2] = '0'; _quoteBuffer[3] = '0'; } /** * Factory method for getting an instance; this is either recycled per-thread instance, * or a newly constructed one. */ public static JsonStringEncoder getInstance() { SoftReference ref = _threadEncoder.get(); JsonStringEncoder enc = (ref == null) ? null : ref.get(); if (enc == null) { enc = new JsonStringEncoder(); _threadEncoder.set(new SoftReference(enc)); } return enc; } /* /********************************************************** /* Public API /********************************************************** */ /** * Method that will quote text contents using JSON standard quoting, * and return results as a character array */ public char[] quoteAsString(String input) { TextBuffer textBuffer = _textBuffer; if (textBuffer == null) { // no allocator; can add if we must, shouldn't need to _textBuffer = textBuffer = new TextBuffer(null); } char[] outputBuffer = textBuffer.emptyAndGetCurrentSegment(); final int[] escCodes = CharTypes.get7BitOutputEscapes(); final int escCodeCount = escCodes.length; int inPtr = 0; final int inputLen = input.length(); int outPtr = 0; outer_loop: while (inPtr < inputLen) { tight_loop: while (true) { char c = input.charAt(inPtr); if (c < escCodeCount && escCodes[c] != 0) { break tight_loop; } if (outPtr >= outputBuffer.length) { outputBuffer = textBuffer.finishCurrentSegment(); outPtr = 0; } outputBuffer[outPtr++] = c; if (++inPtr >= inputLen) { break outer_loop; } } // something to escape; 2 or 6-char variant? int escCode = escCodes[input.charAt(inPtr++)]; int length = _appendSingleEscape(escCode, _quoteBuffer); if ((outPtr + length) > outputBuffer.length) { int first = outputBuffer.length - outPtr; if (first > 0) { System.arraycopy(_quoteBuffer, 0, outputBuffer, outPtr, first); } outputBuffer = textBuffer.finishCurrentSegment(); int second = length - first; System.arraycopy(_quoteBuffer, first, outputBuffer, outPtr, second); outPtr += second; } else { System.arraycopy(_quoteBuffer, 0, outputBuffer, outPtr, length); outPtr += length; } } textBuffer.setCurrentLength(outPtr); return textBuffer.contentsAsArray(); } /** * Will quote given JSON String value using standard quoting, encode * results as UTF-8, and return result as a byte array. */ public byte[] quoteAsUTF8(String text) { ByteArrayBuilder byteBuilder = _byteBuilder; if (byteBuilder == null) { // no allocator; can add if we must, shouldn't need to _byteBuilder = byteBuilder = new ByteArrayBuilder(null); } int inputPtr = 0; int inputEnd = text.length(); int outputPtr = 0; byte[] outputBuffer = byteBuilder.resetAndGetFirstSegment(); main_loop: while (inputPtr < inputEnd) { final int[] escCodes = CharTypes.get7BitOutputEscapes(); inner_loop: // ascii and escapes while (true) { int ch = text.charAt(inputPtr); if (ch > 0x7F || escCodes[ch] != 0) { break inner_loop; } if (outputPtr >= outputBuffer.length) { outputBuffer = byteBuilder.finishCurrentSegment(); outputPtr = 0; } outputBuffer[outputPtr++] = (byte) ch; if (++inputPtr >= inputEnd) { break main_loop; } } if (outputPtr >= outputBuffer.length) { outputBuffer = byteBuilder.finishCurrentSegment(); outputPtr = 0; } // Ok, so what did we hit? int ch = (int) text.charAt(inputPtr++); if (ch <= 0x7F) { // needs quoting int escape = escCodes[ch]; // ctrl-char, 6-byte escape... outputPtr = _appendByteEscape(ch, escape, byteBuilder, outputPtr); outputBuffer = byteBuilder.getCurrentSegment(); continue main_loop; } else if (ch <= 0x7FF) { // fine, just needs 2 byte output outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6)); ch = (0x80 | (ch & 0x3f)); } else { // 3 or 4 bytes // Surrogates? if (ch < SURR1_FIRST || ch > SURR2_LAST) { // nope outputBuffer[outputPtr++] = (byte) (0xe0 | (ch >> 12)); if (outputPtr >= outputBuffer.length) { outputBuffer = byteBuilder.finishCurrentSegment(); outputPtr = 0; } outputBuffer[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f)); ch = (0x80 | (ch & 0x3f)); } else { // yes, surrogate pair if (ch > SURR1_LAST) { // must be from first range _throwIllegalSurrogate(ch); } // and if so, followed by another from next range if (inputPtr >= inputEnd) { _throwIllegalSurrogate(ch); } ch = _convertSurrogate(ch, text.charAt(inputPtr++)); if (ch > 0x10FFFF) { // illegal, as per RFC 4627 _throwIllegalSurrogate(ch); } outputBuffer[outputPtr++] = (byte) (0xf0 | (ch >> 18)); if (outputPtr >= outputBuffer.length) { outputBuffer = byteBuilder.finishCurrentSegment(); outputPtr = 0; } outputBuffer[outputPtr++] = (byte) (0x80 | ((ch >> 12) & 0x3f)); if (outputPtr >= outputBuffer.length) { outputBuffer = byteBuilder.finishCurrentSegment(); outputPtr = 0; } outputBuffer[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f)); ch = (0x80 | (ch & 0x3f)); } } if (outputPtr >= outputBuffer.length) { outputBuffer = byteBuilder.finishCurrentSegment(); outputPtr = 0; } outputBuffer[outputPtr++] = (byte) ch; } return _byteBuilder.completeAndCoalesce(outputPtr); } /** * Will encode given String as UTF-8 (without any quoting), return * resulting byte array. */ public byte[] encodeAsUTF8(String text) { ByteArrayBuilder byteBuilder = _byteBuilder; if (byteBuilder == null) { // no allocator; can add if we must, shouldn't need to _byteBuilder = byteBuilder = new ByteArrayBuilder(null); } int inputPtr = 0; int inputEnd = text.length(); int outputPtr = 0; byte[] outputBuffer = byteBuilder.resetAndGetFirstSegment(); int outputEnd = outputBuffer.length; main_loop: while (inputPtr < inputEnd) { int c = text.charAt(inputPtr++); // first tight loop for ascii while (c <= 0x7F) { if (outputPtr >= outputEnd) { outputBuffer = byteBuilder.finishCurrentSegment(); outputEnd = outputBuffer.length; outputPtr = 0; } outputBuffer[outputPtr++] = (byte) c; if (inputPtr >= inputEnd) { break main_loop; } c = text.charAt(inputPtr++); } // then multi-byte... if (outputPtr >= outputEnd) { outputBuffer = byteBuilder.finishCurrentSegment(); outputEnd = outputBuffer.length; outputPtr = 0; } if (c < 0x800) { // 2-byte outputBuffer[outputPtr++] = (byte) (0xc0 | (c >> 6)); } else { // 3 or 4 bytes // Surrogates? if (c < SURR1_FIRST || c > SURR2_LAST) { // nope outputBuffer[outputPtr++] = (byte) (0xe0 | (c >> 12)); if (outputPtr >= outputEnd) { outputBuffer = byteBuilder.finishCurrentSegment(); outputEnd = outputBuffer.length; outputPtr = 0; } outputBuffer[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); } else { // yes, surrogate pair if (c > SURR1_LAST) { // must be from first range _throwIllegalSurrogate(c); } // and if so, followed by another from next range if (inputPtr >= inputEnd) { _throwIllegalSurrogate(c); } c = _convertSurrogate(c, text.charAt(inputPtr++)); if (c > 0x10FFFF) { // illegal, as per RFC 4627 _throwIllegalSurrogate(c); } outputBuffer[outputPtr++] = (byte) (0xf0 | (c >> 18)); if (outputPtr >= outputEnd) { outputBuffer = byteBuilder.finishCurrentSegment(); outputEnd = outputBuffer.length; outputPtr = 0; } outputBuffer[outputPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); if (outputPtr >= outputEnd) { outputBuffer = byteBuilder.finishCurrentSegment(); outputEnd = outputBuffer.length; outputPtr = 0; } outputBuffer[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); } } if (outputPtr >= outputEnd) { outputBuffer = byteBuilder.finishCurrentSegment(); outputEnd = outputBuffer.length; outputPtr = 0; } outputBuffer[outputPtr++] = (byte) (0x80 | (c & 0x3f)); } return _byteBuilder.completeAndCoalesce(outputPtr); } /* /********************************************************** /* Internal methods /********************************************************** */ private int _appendSingleEscape(int escCode, char[] quoteBuffer) { if (escCode < 0) { // control char, value -(char + 1) int value = -(escCode + 1); quoteBuffer[1] = 'u'; // We know it's a control char, so only the last 2 chars are non-0 quoteBuffer[4] = HEX_CHARS[value >> 4]; quoteBuffer[5] = HEX_CHARS[value & 0xF]; return 6; } quoteBuffer[1] = (char) escCode; return 2; } private int _appendByteEscape(int ch, int escCode, ByteArrayBuilder byteBuilder, int ptr) { byteBuilder.setCurrentSegmentLength(ptr); byteBuilder.append(INT_BACKSLASH); if (escCode < 0) { // standard escape byteBuilder.append(INT_U); if (ch > 0xFF) { int hi = (ch >> 8); byteBuilder.append(HEX_BYTES[hi >> 4]); byteBuilder.append(HEX_BYTES[hi & 0xF]); ch &= 0xFF; } else { byteBuilder.append(INT_0); byteBuilder.append(INT_0); } byteBuilder.append(HEX_BYTES[ch >> 4]); byteBuilder.append(HEX_BYTES[ch & 0xF]); } else { // 2-char simple escape byteBuilder.append((byte) escCode); } return byteBuilder.getCurrentSegmentLength(); } /** * Method called to calculate UTF code point, from a surrogate pair. */ private int _convertSurrogate(int firstPart, int secondPart) { // Ok, then, is the second part valid? if (secondPart < SURR2_FIRST || secondPart > SURR2_LAST) { throw new IllegalArgumentException("Broken surrogate pair: first char 0x"+Integer.toHexString(firstPart)+", second 0x"+Integer.toHexString(secondPart)+"; illegal combination"); } return 0x10000 + ((firstPart - SURR1_FIRST) << 10) + (secondPart - SURR2_FIRST); } private void _throwIllegalSurrogate(int code) { if (code > 0x10FFFF) { // over max? throw new IllegalArgumentException("Illegal character point (0x"+Integer.toHexString(code)+") to output; max is 0x10FFFF as per RFC 4627"); } if (code >= SURR1_FIRST) { if (code <= SURR1_LAST) { // Unmatched first part (closing without second part?) throw new IllegalArgumentException("Unmatched first part of surrogate pair (0x"+Integer.toHexString(code)+")"); } throw new IllegalArgumentException("Unmatched second part of surrogate pair (0x"+Integer.toHexString(code)+")"); } // should we ever get this? throw new IllegalArgumentException("Illegal character point (0x"+Integer.toHexString(code)+") to output"); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/package.html0000644000175000017500000000017211655120726025031 0ustar jamespagejamespage This package contains I/O helper classes Jackson itself uses, but that are not exposed for external reuse. jackson-src-1.9.2/src/java/org/codehaus/jackson/io/SerializedString.java0000644000175000017500000000677711655120726026716 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import org.codehaus.jackson.SerializableString; /** * String token that can lazily serialize String contained and then reuse that * serialization later on. This is similar to JDBC prepared statements, for example, * in that instances should only be created when they are used more than use; * prime candidates are various serializers. *

* Class is final for performance reasons and since this is not designed to * be extensible or customizable (customizations would occur in calling code) * * @since 1.6 */ public class SerializedString implements SerializableString { protected final String _value; /* 13-Dec-2010, tatu: Whether use volatile or not is actually an important * decision for multi-core use cases. Cost of volatility can be non-trivial * for heavy use cases, and serialized-string instances are accessed often. * Given that all code paths with common Jackson usage patterns go through * a few memory barriers (mostly with cache/reuse pool access) it seems safe * enough to omit volatiles here, given how simple lazy initialization is. * This can be compared to how {@link String#intern} works; lazily and * without synchronization or use of volatile keyword. */ protected /*volatile*/ byte[] _quotedUTF8Ref; protected /*volatile*/ byte[] _unquotedUTF8Ref; protected /*volatile*/ char[] _quotedChars; public SerializedString(String v) { _value = v; } /* /********************************************************** /* API /********************************************************** */ @Override public final String getValue() { return _value; } /** * Returns length of the String as characters */ @Override public final int charLength() { return _value.length(); } @Override public final char[] asQuotedChars() { char[] result = _quotedChars; if (result == null) { result = JsonStringEncoder.getInstance().quoteAsString(_value); _quotedChars = result; } return result; } /** * Accessor for accessing value that has been quoted using JSON * quoting rules, and encoded using UTF-8 encoding. */ @Override public final byte[] asUnquotedUTF8() { byte[] result = _unquotedUTF8Ref; if (result == null) { result = JsonStringEncoder.getInstance().encodeAsUTF8(_value); _unquotedUTF8Ref = result; } return result; } /** * Accessor for accessing value as is (without JSON quoting) * encoded using UTF-8 encoding. */ @Override public final byte[] asQuotedUTF8() { byte[] result = _quotedUTF8Ref; if (result == null) { result = JsonStringEncoder.getInstance().quoteAsUTF8(_value); _quotedUTF8Ref = result; } return result; } /* /********************************************************** /* Standard method overrides /********************************************************** */ @Override public final String toString() { return _value; } @Override public final int hashCode() { return _value.hashCode(); } @Override public final boolean equals(Object o) { if (o == this) return true; if (o == null || o.getClass() != getClass()) return false; SerializedString other = (SerializedString) o; return _value.equals(other._value); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/SegmentedStringWriter.java0000644000175000017500000000501711655120726027715 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import java.io.*; import org.codehaus.jackson.util.BufferRecycler; import org.codehaus.jackson.util.TextBuffer; /** * Efficient alternative to {@link StringWriter}, based on using segmented * internal buffer. Initial input buffer is also recyclable. *

* This class is most useful when serializing JSON content as a String: * if so, instance of this class can be given as the writer to * JsonGenerator. * * @since 1.3 */ public final class SegmentedStringWriter extends Writer { final protected TextBuffer _buffer; public SegmentedStringWriter(BufferRecycler br) { super(); _buffer = new TextBuffer(br); } /* /********************************************************** /* java.io.Writer implementation /********************************************************** */ @Override public Writer append(char c) { write(c); return this; } @Override public Writer append(CharSequence csq) { String str = csq.toString(); _buffer.append(str, 0, str.length()); return this; } @Override public Writer append(CharSequence csq, int start, int end) { String str = csq.subSequence(start, end).toString(); _buffer.append(str, 0, str.length()); return this; } @Override public void close() { } // NOP @Override public void flush() { } // NOP @Override public void write(char[] cbuf) { _buffer.append(cbuf, 0, cbuf.length); } @Override public void write(char[] cbuf, int off, int len) { _buffer.append(cbuf, off, len); } @Override public void write(int c) { _buffer.append((char) c); } @Override public void write(String str) { _buffer.append(str, 0, str.length()); } @Override public void write(String str, int off, int len) { _buffer.append(str, 0, str.length()); } /* /********************************************************** /* Extended API /********************************************************** */ /** * Main access method that will construct a String that contains * all the contents, release all internal buffers we may have, * and return result String. * Note that the method is not idempotent -- if called second time, * will just return an empty String. */ public String getAndClear() { String result = _buffer.contentsAsString(); _buffer.releaseBuffers(); return result; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/UTF8Writer.java0000644000175000017500000003113611655120726025342 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import java.io.*; public final class UTF8Writer extends Writer { final static int SURR1_FIRST = 0xD800; final static int SURR1_LAST = 0xDBFF; final static int SURR2_FIRST = 0xDC00; final static int SURR2_LAST = 0xDFFF; final protected IOContext _context; OutputStream _out; byte[] _outBuffer; final int _outBufferEnd; int _outPtr; /** * When outputting chars from BMP, surrogate pairs need to be coalesced. * To do this, both pairs must be known first; and since it is possible * pairs may be split, we need temporary storage for the first half */ int _surrogate = 0; public UTF8Writer(IOContext ctxt, OutputStream out) { _context = ctxt; _out = out; _outBuffer = ctxt.allocWriteEncodingBuffer(); /* Max. expansion for a single char (in unmodified UTF-8) is * 4 bytes (or 3 depending on how you view it -- 4 when recombining * surrogate pairs) */ _outBufferEnd = _outBuffer.length - 4; _outPtr = 0; } @Override public Writer append(char c) throws IOException { write(c); return this; } @Override public void close() throws IOException { if (_out != null) { if (_outPtr > 0) { _out.write(_outBuffer, 0, _outPtr); _outPtr = 0; } OutputStream out = _out; _out = null; byte[] buf = _outBuffer; if (buf != null) { _outBuffer = null; _context.releaseWriteEncodingBuffer(buf); } out.close(); /* Let's 'flush' orphan surrogate, no matter what; but only * after cleanly closing everything else. */ int code = _surrogate; _surrogate = 0; if (code > 0) { throwIllegal(code); } } } @Override public void flush() throws IOException { if (_out != null) { if (_outPtr > 0) { _out.write(_outBuffer, 0, _outPtr); _outPtr = 0; } _out.flush(); } } @Override public void write(char[] cbuf) throws IOException { write(cbuf, 0, cbuf.length); } @Override public void write(char[] cbuf, int off, int len) throws IOException { if (len < 2) { if (len == 1) { write(cbuf[off]); } return; } // First: do we have a leftover surrogate to deal with? if (_surrogate > 0) { char second = cbuf[off++]; --len; write(convertSurrogate(second)); // will have at least one more char } int outPtr = _outPtr; byte[] outBuf = _outBuffer; int outBufLast = _outBufferEnd; // has 4 'spare' bytes // All right; can just loop it nice and easy now: len += off; // len will now be the end of input buffer output_loop: for (; off < len; ) { /* First, let's ensure we can output at least 4 bytes * (longest UTF-8 encoded codepoint): */ if (outPtr >= outBufLast) { _out.write(outBuf, 0, outPtr); outPtr = 0; } int c = cbuf[off++]; // And then see if we have an Ascii char: if (c < 0x80) { // If so, can do a tight inner loop: outBuf[outPtr++] = (byte)c; // Let's calc how many ascii chars we can copy at most: int maxInCount = (len - off); int maxOutCount = (outBufLast - outPtr); if (maxInCount > maxOutCount) { maxInCount = maxOutCount; } maxInCount += off; ascii_loop: while (true) { if (off >= maxInCount) { // done with max. ascii seq continue output_loop; } c = cbuf[off++]; if (c >= 0x80) { break ascii_loop; } outBuf[outPtr++] = (byte) c; } } // Nope, multi-byte: if (c < 0x800) { // 2-byte outBuf[outPtr++] = (byte) (0xc0 | (c >> 6)); outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); } else { // 3 or 4 bytes // Surrogates? if (c < SURR1_FIRST || c > SURR2_LAST) { outBuf[outPtr++] = (byte) (0xe0 | (c >> 12)); outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); continue; } // Yup, a surrogate: if (c > SURR1_LAST) { // must be from first range _outPtr = outPtr; throwIllegal(c); } _surrogate = c; // and if so, followed by another from next range if (off >= len) { // unless we hit the end? break; } c = convertSurrogate(cbuf[off++]); if (c > 0x10FFFF) { // illegal in JSON as well as in XML _outPtr = outPtr; throwIllegal(c); } outBuf[outPtr++] = (byte) (0xf0 | (c >> 18)); outBuf[outPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); } } _outPtr = outPtr; } @Override public void write(int c) throws IOException { // First; do we have a left over surrogate? if (_surrogate > 0) { c = convertSurrogate(c); // If not, do we start with a surrogate? } else if (c >= SURR1_FIRST && c <= SURR2_LAST) { // Illegal to get second part without first: if (c > SURR1_LAST) { throwIllegal(c); } // First part just needs to be held for now _surrogate = c; return; } if (_outPtr >= _outBufferEnd) { // let's require enough room, first _out.write(_outBuffer, 0, _outPtr); _outPtr = 0; } if (c < 0x80) { // ascii _outBuffer[_outPtr++] = (byte) c; } else { int ptr = _outPtr; if (c < 0x800) { // 2-byte _outBuffer[ptr++] = (byte) (0xc0 | (c >> 6)); _outBuffer[ptr++] = (byte) (0x80 | (c & 0x3f)); } else if (c <= 0xFFFF) { // 3 bytes _outBuffer[ptr++] = (byte) (0xe0 | (c >> 12)); _outBuffer[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); _outBuffer[ptr++] = (byte) (0x80 | (c & 0x3f)); } else { // 4 bytes if (c > 0x10FFFF) { // illegal throwIllegal(c); } _outBuffer[ptr++] = (byte) (0xf0 | (c >> 18)); _outBuffer[ptr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); _outBuffer[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); _outBuffer[ptr++] = (byte) (0x80 | (c & 0x3f)); } _outPtr = ptr; } } @Override public void write(String str) throws IOException { write(str, 0, str.length()); } @Override public void write(String str, int off, int len) throws IOException { if (len < 2) { if (len == 1) { write(str.charAt(off)); } return; } // First: do we have a leftover surrogate to deal with? if (_surrogate > 0) { char second = str.charAt(off++); --len; write(convertSurrogate(second)); // will have at least one more char (case of 1 char was checked earlier on) } int outPtr = _outPtr; byte[] outBuf = _outBuffer; int outBufLast = _outBufferEnd; // has 4 'spare' bytes // All right; can just loop it nice and easy now: len += off; // len will now be the end of input buffer output_loop: for (; off < len; ) { /* First, let's ensure we can output at least 4 bytes * (longest UTF-8 encoded codepoint): */ if (outPtr >= outBufLast) { _out.write(outBuf, 0, outPtr); outPtr = 0; } int c = str.charAt(off++); // And then see if we have an Ascii char: if (c < 0x80) { // If so, can do a tight inner loop: outBuf[outPtr++] = (byte)c; // Let's calc how many ascii chars we can copy at most: int maxInCount = (len - off); int maxOutCount = (outBufLast - outPtr); if (maxInCount > maxOutCount) { maxInCount = maxOutCount; } maxInCount += off; ascii_loop: while (true) { if (off >= maxInCount) { // done with max. ascii seq continue output_loop; } c = str.charAt(off++); if (c >= 0x80) { break ascii_loop; } outBuf[outPtr++] = (byte) c; } } // Nope, multi-byte: if (c < 0x800) { // 2-byte outBuf[outPtr++] = (byte) (0xc0 | (c >> 6)); outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); } else { // 3 or 4 bytes // Surrogates? if (c < SURR1_FIRST || c > SURR2_LAST) { outBuf[outPtr++] = (byte) (0xe0 | (c >> 12)); outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); continue; } // Yup, a surrogate: if (c > SURR1_LAST) { // must be from first range _outPtr = outPtr; throwIllegal(c); } _surrogate = c; // and if so, followed by another from next range if (off >= len) { // unless we hit the end? break; } c = convertSurrogate(str.charAt(off++)); if (c > 0x10FFFF) { // illegal, as per RFC 4627 _outPtr = outPtr; throwIllegal(c); } outBuf[outPtr++] = (byte) (0xf0 | (c >> 18)); outBuf[outPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f)); } } _outPtr = outPtr; } /* /********************************************************** /* Internal methods /********************************************************** */ /** * Method called to calculate UTF codepoint, from a surrogate pair. */ private int convertSurrogate(int secondPart) throws IOException { int firstPart = _surrogate; _surrogate = 0; // Ok, then, is the second part valid? if (secondPart < SURR2_FIRST || secondPart > SURR2_LAST) { throw new IOException("Broken surrogate pair: first char 0x"+Integer.toHexString(firstPart)+", second 0x"+Integer.toHexString(secondPart)+"; illegal combination"); } return 0x10000 + ((firstPart - SURR1_FIRST) << 10) + (secondPart - SURR2_FIRST); } private void throwIllegal(int code) throws IOException { if (code > 0x10FFFF) { // over max? throw new IOException("Illegal character point (0x"+Integer.toHexString(code)+") to output; max is 0x10FFFF as per RFC 4627"); } if (code >= SURR1_FIRST) { if (code <= SURR1_LAST) { // Unmatched first part (closing without second part?) throw new IOException("Unmatched first part of surrogate pair (0x"+Integer.toHexString(code)+")"); } throw new IOException("Unmatched second part of surrogate pair (0x"+Integer.toHexString(code)+")"); } // should we ever get this? throw new IOException("Illegal character point (0x"+Integer.toHexString(code)+") to output"); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/OutputDecorator.java0000644000175000017500000000257111655120726026563 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import java.io.*; /** * Handler class that can be used to decorate output destinations. * Typical use is to use a filter abstraction (filtered output stream, * writer) around original output destination, and apply additional * processing during write operations. * * @since 1.8 */ public abstract class OutputDecorator { /** * Method called by {@link org.codehaus.jackson.JsonFactory} instance when * creating generator for given {@link OutputStream}, when this decorator * has been registered. * * @param ctxt IO context in use (provides access to declared encoding) * @param out Original output destination * * @return OutputStream to use; either passed in argument, or something that * calls it */ public abstract OutputStream decorate(IOContext ctxt, OutputStream out) throws IOException; /** * Method called by {@link org.codehaus.jackson.JsonFactory} instance when * creating generator for given {@link Writer}, when this decorator * has been registered. * * @param ctxt IO context in use (provides access to declared encoding) * @param w Original output writer * * @return Writer to use; either passed in argument, or something that calls it */ public abstract Writer decorate(IOContext ctxt, Writer w) throws IOException; } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/CharacterEscapes.java0000644000175000017500000000542411655120726026620 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import org.codehaus.jackson.SerializableString; import org.codehaus.jackson.util.CharTypes; /** * Abstract base class that defines interface for customizing character * escaping aspects for String values, for formats that use escaping. * For JSON this applies to both property names and String values. * * @since 1.8 */ public abstract class CharacterEscapes { /** * Value used for lookup tables to indicate that matching characters * do not need to be escaped. */ public final static int ESCAPE_NONE = 0; /** * Value used for lookup tables to indicate that matching characters * are to be escaped using standard escaping; for JSON this means * (for example) using "backslash - u" escape method. */ public final static int ESCAPE_STANDARD = -1; /** * Value used for lookup tables to indicate that matching characters * will need custom escapes; and that another call * to {@link #getEscapeSequence} is needed to figure out exact escape * sequence to output. */ public final static int ESCAPE_CUSTOM = -2; /** * Method generators can call to get lookup table for determining * escape handling for first 128 characters of Unicode (ASCII * characters. Caller is not to modify contents of this array, since * this is expected to be a shared copy. * * @return Array with size of at least 128, where first 128 entries * have either one of ESCAPE_xxx constants, or non-zero positive * integer (meaning of which is data format specific; for JSON it means * that combination of backslash and character with that value is to be used) * to indicate that specific escape sequence is to be used. */ public abstract int[] getEscapeCodesForAscii(); /** * Method generators can call to get lookup table for determining * exact escape sequence to use for given character. * It can be called for any character, but typically is called for * either for ASCII characters for which custom escape * sequence is needed; or for any non-ASCII character. */ public abstract SerializableString getEscapeSequence(int ch); /** * Helper method that can be used to get a copy of standard JSON * escape definitions; this is useful when just wanting to slightly * customize definitions. Caller can modify this array as it sees * fit and usually returns modified instance via {@link #getEscapeCodesForAscii} */ public static int[] standardAsciiEscapesForJSON() { int[] esc = CharTypes.get7BitOutputEscapes(); int len = esc.length; int[] result = new int[len]; System.arraycopy(esc, 0, result, 0, esc.length); return result; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/IOContext.java0000644000175000017500000002003411655120726025266 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import org.codehaus.jackson.JsonEncoding; import org.codehaus.jackson.util.BufferRecycler; import org.codehaus.jackson.util.TextBuffer; /** * To limit number of configuration and state objects to pass, all * contextual objects that need to be passed by the factory to * readers and writers are combined under this object. One instance * is created for each reader and writer. */ public final class IOContext { /* /********************************************************** /* Configuration /********************************************************** */ /** * Reference to the source object, which can be used for displaying * location information */ protected final Object _sourceRef; /** * Encoding used by the underlying stream, if known. */ protected JsonEncoding _encoding; /** * Flag that indicates whether underlying input/output source/target * object is fully managed by the owner of this context (parser or * generator). If true, it is, and is to be closed by parser/generator; * if false, calling application has to do closing (unless auto-closing * feature is enabled for the parser/generator in question; in which * case it acts like the owner). */ protected final boolean _managedResource; /* /********************************************************** /* Buffer handling, recycling /********************************************************** */ /** * Recycler used for actual allocation/deallocation/reuse */ protected final BufferRecycler _bufferRecycler; /** * Reference to the allocated I/O buffer for low-level input reading, * if any allocated. */ protected byte[] _readIOBuffer = null; /** * Reference to the allocated I/O buffer used for low-level * encoding-related buffering. */ protected byte[] _writeEncodingBuffer = null; /** * Reference to the buffer allocated for tokenization purposes, * in which character input is read, and from which it can be * further returned. */ protected char[] _tokenCBuffer = null; /** * Reference to the buffer allocated for buffering it for * output, before being encoded: generally this means concatenating * output, then encoding when buffer fills up. */ protected char[] _concatCBuffer = null; /** * Reference temporary buffer Parser instances need if calling * app decides it wants to access name via 'getTextCharacters' method. * Regular text buffer can not be used as it may contain textual * representation of the value token. */ protected char[] _nameCopyBuffer = null; /* /********************************************************** /* Life-cycle /********************************************************** */ public IOContext(BufferRecycler br, Object sourceRef, boolean managedResource) { _bufferRecycler = br; _sourceRef = sourceRef; _managedResource = managedResource; } public void setEncoding(JsonEncoding enc) { _encoding = enc; } /* /********************************************************** /* Public API, accessors /********************************************************** */ public final Object getSourceReference() { return _sourceRef; } public final JsonEncoding getEncoding() { return _encoding; } public final boolean isResourceManaged() { return _managedResource; } /* /********************************************************** /* Public API, buffer management /********************************************************** */ public final TextBuffer constructTextBuffer() { return new TextBuffer(_bufferRecycler); } /** *

* Note: the method can only be called once during its life cycle. * This is to protect against accidental sharing. */ public final byte[] allocReadIOBuffer() { if (_readIOBuffer != null) { throw new IllegalStateException("Trying to call allocReadIOBuffer() second time"); } _readIOBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.READ_IO_BUFFER); return _readIOBuffer; } public final byte[] allocWriteEncodingBuffer() { if (_writeEncodingBuffer != null) { throw new IllegalStateException("Trying to call allocWriteEncodingBuffer() second time"); } _writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.ByteBufferType.WRITE_ENCODING_BUFFER); return _writeEncodingBuffer; } public final char[] allocTokenBuffer() { if (_tokenCBuffer != null) { throw new IllegalStateException("Trying to call allocTokenBuffer() second time"); } _tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.TOKEN_BUFFER); return _tokenCBuffer; } public final char[] allocConcatBuffer() { if (_concatCBuffer != null) { throw new IllegalStateException("Trying to call allocConcatBuffer() second time"); } _concatCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.CONCAT_BUFFER); return _concatCBuffer; } public final char[] allocNameCopyBuffer(int minSize) { if (_nameCopyBuffer != null) { throw new IllegalStateException("Trying to call allocNameCopyBuffer() second time"); } _nameCopyBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CharBufferType.NAME_COPY_BUFFER, minSize); return _nameCopyBuffer; } /** * Method to call when all the processing buffers can be safely * recycled. */ public final void releaseReadIOBuffer(byte[] buf) { if (buf != null) { /* Let's do sanity checks to ensure once-and-only-once release, * as well as avoiding trying to release buffers not owned */ if (buf != _readIOBuffer) { throw new IllegalArgumentException("Trying to release buffer not owned by the context"); } _readIOBuffer = null; _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.READ_IO_BUFFER, buf); } } public final void releaseWriteEncodingBuffer(byte[] buf) { if (buf != null) { /* Let's do sanity checks to ensure once-and-only-once release, * as well as avoiding trying to release buffers not owned */ if (buf != _writeEncodingBuffer) { throw new IllegalArgumentException("Trying to release buffer not owned by the context"); } _writeEncodingBuffer = null; _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.WRITE_ENCODING_BUFFER, buf); } } public final void releaseTokenBuffer(char[] buf) { if (buf != null) { if (buf != _tokenCBuffer) { throw new IllegalArgumentException("Trying to release buffer not owned by the context"); } _tokenCBuffer = null; _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.TOKEN_BUFFER, buf); } } public final void releaseConcatBuffer(char[] buf) { if (buf != null) { if (buf != _concatCBuffer) { throw new IllegalArgumentException("Trying to release buffer not owned by the context"); } _concatCBuffer = null; _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.CONCAT_BUFFER, buf); } } public final void releaseNameCopyBuffer(char[] buf) { if (buf != null) { if (buf != _nameCopyBuffer) { throw new IllegalArgumentException("Trying to release buffer not owned by the context"); } _nameCopyBuffer = null; _bufferRecycler.releaseCharBuffer(BufferRecycler.CharBufferType.NAME_COPY_BUFFER, buf); } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/io/MergedStream.java0000644000175000017500000000627211655120726026001 0ustar jamespagejamespagepackage org.codehaus.jackson.io; import java.io.*; /** * Simple {@link InputStream} implementation that is used to "unwind" some * data previously read from an input stream; so that as long as some of * that data remains, it's returned; but as long as it's read, we'll * just use data from the underlying original stream. * This is similar to {@link java.io.PushbackInputStream}, but here there's * only one implicit pushback, when instance is constructed. */ public final class MergedStream extends InputStream { final protected IOContext _context; final InputStream _in; byte[] _buffer; int _ptr; final int _end; public MergedStream(IOContext context, InputStream in, byte[] buf, int start, int end) { _context = context; _in = in; _buffer = buf; _ptr = start; _end = end; } @Override public int available() throws IOException { if (_buffer != null) { return _end - _ptr; } return _in.available(); } @Override public void close() throws IOException { freeMergedBuffer(); _in.close(); } @Override public void mark(int readlimit) { if (_buffer == null) { _in.mark(readlimit); } } @Override public boolean markSupported() { // Only supports marks past the initial rewindable section... return (_buffer == null) && _in.markSupported(); } @Override public int read() throws IOException { if (_buffer != null) { int c = _buffer[_ptr++] & 0xFF; if (_ptr >= _end) { freeMergedBuffer(); } return c; } return _in.read(); } @Override public int read(byte[] b) throws IOException { return read(b, 0, b.length); } @Override public int read(byte[] b, int off, int len) throws IOException { if (_buffer != null) { int avail = _end - _ptr; if (len > avail) { len = avail; } System.arraycopy(_buffer, _ptr, b, off, len); _ptr += len; if (_ptr >= _end) { freeMergedBuffer(); } return len; } return _in.read(b, off, len); } @Override public void reset() throws IOException { if (_buffer == null) { _in.reset(); } } @Override public long skip(long n) throws IOException { long count = 0L; if (_buffer != null) { int amount = _end - _ptr; if (amount > n) { // all in pushed back segment? _ptr += (int) n; return n; } freeMergedBuffer(); count += amount; n -= amount; } if (n > 0) { count += _in.skip(n); } return count; } private void freeMergedBuffer() { byte[] buf = _buffer; if (buf != null) { _buffer = null; if (_context != null) { _context.releaseReadIOBuffer(buf); } } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/0000755000175000017500000000000011672662540023122 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/util/MinimalPrettyPrinter.java0000644000175000017500000001052111655120726030122 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.io.IOException; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.PrettyPrinter; /** * {@link PrettyPrinter} implementation that adds no indentation, * just implements everything necessary for value output to work * as expected, and provide simpler extension points to allow * for creating simple custom implementations that add specific * decoration or overrides. Since behavior then is very similar * to using no pretty printer at all, usually sub-classes are used. *

* Beyond purely minimal implementation, there is limited amount of * configurability which may be useful for actual use: for example, * it is possible to redefine separator used between root-level * values (default is single space; can be changed to line-feed). * * @since 1.6 */ public class MinimalPrettyPrinter implements PrettyPrinter { /** * Default String used for separating root values is single space. */ public final static String DEFAULT_ROOT_VALUE_SEPARATOR = " "; protected String _rootValueSeparator = DEFAULT_ROOT_VALUE_SEPARATOR; /* /********************************************************** /* Life-cycle, construction, configuration /********************************************************** */ public MinimalPrettyPrinter() { this(DEFAULT_ROOT_VALUE_SEPARATOR); } /** * @since 1.9 */ public MinimalPrettyPrinter(String rootValueSeparator) { _rootValueSeparator = rootValueSeparator; } public void setRootValueSeparator(String sep) { _rootValueSeparator = sep; } /* /********************************************************** /* PrettyPrinter impl /********************************************************** */ @Override public void writeRootValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException { if (_rootValueSeparator != null) { jg.writeRaw(_rootValueSeparator); } } @Override public void writeStartObject(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw('{'); } @Override public void beforeObjectEntries(JsonGenerator jg) throws IOException, JsonGenerationException { // nothing special, since no indentation is added } /** * Method called after an object field has been output, but * before the value is output. *

* Default handling will just output a single * colon to separate the two, without additional spaces. */ @Override public void writeObjectFieldValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw(':'); } /** * Method called after an object entry (field:value) has been completely * output, and before another value is to be output. *

* Default handling (without pretty-printing) will output a single * comma to separate the two. */ @Override public void writeObjectEntrySeparator(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw(','); } @Override public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException, JsonGenerationException { jg.writeRaw('}'); } @Override public void writeStartArray(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw('['); } @Override public void beforeArrayValues(JsonGenerator jg) throws IOException, JsonGenerationException { // nothing special, since no indentation is added } /** * Method called after an array value has been completely * output, and before another value is to be output. *

* Default handling (without pretty-printing) will output a single * comma to separate values. */ @Override public void writeArrayValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw(','); } @Override public void writeEndArray(JsonGenerator jg, int nrOfValues) throws IOException, JsonGenerationException { jg.writeRaw(']'); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/VersionUtil.java0000644000175000017500000000510311655120726026243 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.io.*; import java.util.regex.Pattern; import org.codehaus.jackson.Version; /** * Functionality for supporting exposing of component {@link Version}s. * * @since 1.6 */ public class VersionUtil { public final static String VERSION_FILE = "VERSION.txt"; private final static Pattern VERSION_SEPARATOR = Pattern.compile("[-_./;:]"); /** * Helper method that will try to load version information for specified * class. Implementation is simple: class loader that loaded specified * class is asked to load resource with name "VERSION" from same * location (package) as class itself had. * If no version information is found, {@link Version#unknownVersion()} is * returned. */ public static Version versionFor(Class cls) { InputStream in; Version version = null; try { in = cls.getResourceAsStream(VERSION_FILE); if (in != null) { try { BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); version = parseVersion(br.readLine()); } finally { try { in.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } catch (IOException e) { } return (version == null) ? Version.unknownVersion() : version; } public static Version parseVersion(String versionStr) { if (versionStr == null) return null; versionStr = versionStr.trim(); if (versionStr.length() == 0) return null; String[] parts = VERSION_SEPARATOR.split(versionStr); // Let's not bother if there's no separate parts; otherwise use whatever we got if (parts.length < 2) { return null; } int major = parseVersionPart(parts[0]); int minor = parseVersionPart(parts[1]); int patch = (parts.length > 2) ? parseVersionPart(parts[2]) : 0; String snapshot = (parts.length > 3) ? parts[3] : null; return new Version(major, minor, patch, snapshot); } protected static int parseVersionPart(String partStr) { partStr = partStr.toString(); int len = partStr.length(); int number = 0; for (int i = 0; i < len; ++i) { char c = partStr.charAt(i); if (c > '9' || c < '0') break; number = (number * 10) + (c - '0'); } return number; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/InternCache.java0000644000175000017500000000247411655120726026153 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.util.Map; import java.util.LinkedHashMap; /** * Singleton class that adds a simple first-level cache in front of * regular String.intern() functionality. This is done as a minor * performance optimization, to avoid calling native intern() method * in cases where same String is being interned multiple times. *

* Note: that this class extends {@link LinkedHashMap} is an implementation * detail -- no code should ever directly call Map methods. */ @SuppressWarnings("serial") public final class InternCache extends LinkedHashMap { /** * Size to use is somewhat arbitrary, so let's choose something that's * neither too small (low hit ratio) nor too large (waste of memory) */ private final static int MAX_ENTRIES = 192; public final static InternCache instance = new InternCache(); private InternCache() { super(MAX_ENTRIES, 0.8f, true); } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_ENTRIES; } public synchronized String intern(String input) { String result = get(input); if (result == null) { result = input.intern(); put(result, result); } return result; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/ByteArrayBuilder.java0000644000175000017500000002072211655120726027175 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson.util; import java.io.OutputStream; import java.util.*; /** * Helper class that is similar to {@link java.io.ByteArrayOutputStream} * in usage, but more geared to Jackson use cases internally. * Specific changes include segment storage (no need to have linear * backing buffer, can avoid reallocs, copying), as well API * not based on {@link java.io.OutputStream}. In short, a very much * specialized builder object. *

* Since version 1.5, also implements {@link OutputStream} to allow * efficient aggregation of output content as a byte array, similar * to how {@link java.io.ByteArrayOutputStream} works, but somewhat more * efficiently for many use cases. */ public final class ByteArrayBuilder extends OutputStream { private final static byte[] NO_BYTES = new byte[0]; /** * Size of the first block we will allocate. */ private final static int INITIAL_BLOCK_SIZE = 500; /** * Maximum block size we will use for individual non-aggregated * blocks. Let's limit to using 256k chunks. */ private final static int MAX_BLOCK_SIZE = (1 << 18); final static int DEFAULT_BLOCK_ARRAY_SIZE = 40; /** * Optional buffer recycler instance that we can use for allocating * the first block. * * @since 1.5 */ private final BufferRecycler _bufferRecycler; private final LinkedList _pastBlocks = new LinkedList(); /** * Number of bytes within byte arrays in {@link _pastBlocks}. */ private int _pastLen; private byte[] _currBlock; private int _currBlockPtr; public ByteArrayBuilder() { this(null); } public ByteArrayBuilder(BufferRecycler br) { this(br, INITIAL_BLOCK_SIZE); } public ByteArrayBuilder(int firstBlockSize) { this(null, firstBlockSize); } public ByteArrayBuilder(BufferRecycler br, int firstBlockSize) { _bufferRecycler = br; if (br == null) { _currBlock = new byte[firstBlockSize]; } else { _currBlock = br.allocByteBuffer(BufferRecycler.ByteBufferType.WRITE_CONCAT_BUFFER); } } public void reset() { _pastLen = 0; _currBlockPtr = 0; if (!_pastBlocks.isEmpty()) { _pastBlocks.clear(); } } /** * Clean up method to call to release all buffers this object may be * using. After calling the method, no other accessors can be used (and * attempt to do so may result in an exception) */ public void release() { reset(); if (_bufferRecycler != null && _currBlock != null) { _bufferRecycler.releaseByteBuffer(BufferRecycler.ByteBufferType.WRITE_CONCAT_BUFFER, _currBlock); _currBlock = null; } } public void append(int i) { if (_currBlockPtr >= _currBlock.length) { _allocMore(); } _currBlock[_currBlockPtr++] = (byte) i; } public void appendTwoBytes(int b16) { if ((_currBlockPtr + 1) < _currBlock.length) { _currBlock[_currBlockPtr++] = (byte) (b16 >> 8); _currBlock[_currBlockPtr++] = (byte) b16; } else { append(b16 >> 8); append(b16); } } public void appendThreeBytes(int b24) { if ((_currBlockPtr + 2) < _currBlock.length) { _currBlock[_currBlockPtr++] = (byte) (b24 >> 16); _currBlock[_currBlockPtr++] = (byte) (b24 >> 8); _currBlock[_currBlockPtr++] = (byte) b24; } else { append(b24 >> 16); append(b24 >> 8); append(b24); } } /** * Method called when results are finalized and we can get the * full aggregated result buffer to return to the caller */ public byte[] toByteArray() { int totalLen = _pastLen + _currBlockPtr; if (totalLen == 0) { // quick check: nothing aggregated? return NO_BYTES; } byte[] result = new byte[totalLen]; int offset = 0; for (byte[] block : _pastBlocks) { int len = block.length; System.arraycopy(block, 0, result, offset, len); offset += len; } System.arraycopy(_currBlock, 0, result, offset, _currBlockPtr); offset += _currBlockPtr; if (offset != totalLen) { // just a sanity check throw new RuntimeException("Internal error: total len assumed to be "+totalLen+", copied "+offset+" bytes"); } // Let's only reset if there's sizable use, otherwise will get reset later on if (!_pastBlocks.isEmpty()) { reset(); } return result; } /* /********************************************************** /* Non-stream API (similar to TextBuffer), since 1.6 /********************************************************** */ /** * Method called when starting "manual" output: will clear out * current state and return the first segment buffer to fill * * @since 1.6 */ public byte[] resetAndGetFirstSegment() { reset(); return _currBlock; } /** * Method called when the current segment buffer is full; will * append to current contents, allocate a new segment buffer * and return it * * @since 1.6 */ public byte[] finishCurrentSegment() { _allocMore(); return _currBlock; } /** * Method that will complete "manual" output process, coalesce * content (if necessary) and return results as a contiguous buffer. * * @param lastBlockLength Amount of content in the current segment * buffer. * * @return Coalesced contents */ public byte[] completeAndCoalesce(int lastBlockLength) { _currBlockPtr = lastBlockLength; return toByteArray(); } public byte[] getCurrentSegment() { return _currBlock; } public void setCurrentSegmentLength(int len) { _currBlockPtr = len; } public int getCurrentSegmentLength() { return _currBlockPtr; } /* /********************************************************** /* OutputStream implementation /********************************************************** */ @Override public void write(byte[] b) { write(b, 0, b.length); } @Override public void write(byte[] b, int off, int len) { while (true) { int max = _currBlock.length - _currBlockPtr; int toCopy = Math.min(max, len); if (toCopy > 0) { System.arraycopy(b, off, _currBlock, _currBlockPtr, toCopy); off += toCopy; _currBlockPtr += toCopy; len -= toCopy; } if (len <= 0) break; _allocMore(); } } @Override public void write(int b) { append(b); } @Override public void close() { /* NOP */ } @Override public void flush() { /* NOP */ } /* /********************************************************** /* Internal methods /********************************************************** */ private void _allocMore() { _pastLen += _currBlock.length; /* Let's allocate block that's half the total size, except * never smaller than twice the initial block size. * The idea is just to grow with reasonable rate, to optimize * between minimal number of chunks and minimal amount of * wasted space. */ int newSize = Math.max((_pastLen >> 1), (INITIAL_BLOCK_SIZE + INITIAL_BLOCK_SIZE)); // plus not to exceed max we define... if (newSize > MAX_BLOCK_SIZE) { newSize = MAX_BLOCK_SIZE; } _pastBlocks.add(_currBlock); _currBlock = new byte[newSize]; _currBlockPtr = 0; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/JsonParserSequence.java0000644000175000017500000001070611655120726027544 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.io.IOException; import java.util.*; import org.codehaus.jackson.*; /** * Helper class that can be used to sequence multiple physical * {@link JsonParser}s to create a single logical sequence of * tokens, as a single {@link JsonParser}. *

* Fairly simple use of {@link JsonParserDelegate}: only need * to override {@link #nextToken} to handle transition * * @author tatu * @since 1.5 */ public class JsonParserSequence extends JsonParserDelegate { /** * Parsers other than the first one (which is initially assigned * as delegate) */ protected final JsonParser[] _parsers; /** * Index of the next parser in {@link #_parsers}. */ protected int _nextParser; /* ******************************************************* * Construction ******************************************************* */ protected JsonParserSequence(JsonParser[] parsers) { super(parsers[0]); _parsers = parsers; _nextParser = 1; } /** * Method that will construct a parser (possibly a sequence) that * contains all given sub-parsers. * All parsers given are checked to see if they are sequences: and * if so, they will be "flattened", that is, contained parsers are * directly added in a new sequence instead of adding sequences * within sequences. This is done to minimize delegation depth, * ideally only having just a single level of delegation. */ public static JsonParserSequence createFlattened(JsonParser first, JsonParser second) { if (!(first instanceof JsonParserSequence || second instanceof JsonParserSequence)) { // simple: return new JsonParserSequence(new JsonParser[] { first, second }); } ArrayList p = new ArrayList(); if (first instanceof JsonParserSequence) { ((JsonParserSequence) first).addFlattenedActiveParsers(p); } else { p.add(first); } if (second instanceof JsonParserSequence) { ((JsonParserSequence) second).addFlattenedActiveParsers(p); } else { p.add(second); } return new JsonParserSequence(p.toArray(new JsonParser[p.size()])); } protected void addFlattenedActiveParsers(List result) { for (int i = _nextParser-1, len = _parsers.length; i < len; ++i) { JsonParser p = _parsers[i]; if (p instanceof JsonParserSequence) { ((JsonParserSequence) p).addFlattenedActiveParsers(result); } else { result.add(p); } } } /* ******************************************************* * Overridden methods, needed: cases where default * delegation does not work ******************************************************* */ @Override public void close() throws IOException { do { delegate.close(); } while (switchToNext()); } @Override public JsonToken nextToken() throws IOException, JsonParseException { JsonToken t = delegate.nextToken(); if (t != null) return t; while (switchToNext()) { t = delegate.nextToken(); if (t != null) return t; } return null; } /* /******************************************************* /* Additional extended API /******************************************************* */ /** * Method that is most useful for debugging or testing; * returns actual number of underlying parsers sequence * was constructed with (nor just ones remaining active) */ public int containedParsersCount() { return _parsers.length; } /* /******************************************************* /* Helper methods /******************************************************* */ /** * Method that will switch active parser from the current one * to next parser in sequence, if there is another parser left, * making this the new delegate. Old delegate is returned if * switch succeeds. * * @return True if switch succeeded; false otherwise */ protected boolean switchToNext() { if (_nextParser >= _parsers.length) { return false; } delegate = _parsers[_nextParser++]; return true; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/package-info.java0000644000175000017500000000014211655120726026302 0ustar jamespagejamespage/** * Utility classes used by Jackson Core functionality. */ package org.codehaus.jackson.util; jackson-src-1.9.2/src/java/org/codehaus/jackson/util/DefaultPrettyPrinter.java0000644000175000017500000001771711655120726030136 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.io.*; import java.util.Arrays; import org.codehaus.jackson.*; import org.codehaus.jackson.impl.Indenter; /** * Default {@link PrettyPrinter} implementation that uses 2-space * indentation with platform-default linefeeds. * Usually this class is not instantiated directly, but instead * method {@link JsonGenerator#useDefaultPrettyPrinter} is * used, which will use an instance of this class for operation. */ public class DefaultPrettyPrinter implements PrettyPrinter { // // // Config, indentation /** * By default, let's use only spaces to separate array values. */ protected Indenter _arrayIndenter = new FixedSpaceIndenter(); /** * By default, let's use linefeed-adding indenter for separate * object entries. We'll further configure indenter to use * system-specific linefeeds, and 2 spaces per level (as opposed to, * say, single tabs) */ protected Indenter _objectIndenter = new Lf2SpacesIndenter(); // // // Config, other white space configuration /** * By default we will add spaces around colons used to * separate object fields and values. * If disabled, will not use spaces around colon. */ protected boolean _spacesInObjectEntries = true; // // // State: /** * Number of open levels of nesting. Used to determine amount of * indentation to use. */ protected int _nesting = 0; /* /********************************************************** /* Life-cycle (construct, configure) /********************************************************** */ public DefaultPrettyPrinter() { } public void indentArraysWith(Indenter i) { _arrayIndenter = (i == null) ? new NopIndenter() : i; } public void indentObjectsWith(Indenter i) { _objectIndenter = (i == null) ? new NopIndenter() : i; } public void spacesInObjectEntries(boolean b) { _spacesInObjectEntries = b; } /* /********************************************************** /* PrettyPrinter impl /********************************************************** */ @Override public void writeRootValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw(' '); } @Override public void writeStartObject(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw('{'); if (!_objectIndenter.isInline()) { ++_nesting; } } @Override public void beforeObjectEntries(JsonGenerator jg) throws IOException, JsonGenerationException { _objectIndenter.writeIndentation(jg, _nesting); } /** * Method called after an object field has been output, but * before the value is output. *

* Default handling (without pretty-printing) will output a single * colon to separate the two. Pretty-printer is * to output a colon as well, but can surround that with other * (white-space) decoration. */ @Override public void writeObjectFieldValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException { if (_spacesInObjectEntries) { jg.writeRaw(" : "); } else { jg.writeRaw(':'); } } /** * Method called after an object entry (field:value) has been completely * output, and before another value is to be output. *

* Default handling (without pretty-printing) will output a single * comma to separate the two. Pretty-printer is * to output a comma as well, but can surround that with other * (white-space) decoration. */ @Override public void writeObjectEntrySeparator(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw(','); _objectIndenter.writeIndentation(jg, _nesting); } @Override public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException, JsonGenerationException { if (!_objectIndenter.isInline()) { --_nesting; } if (nrOfEntries > 0) { _objectIndenter.writeIndentation(jg, _nesting); } else { jg.writeRaw(' '); } jg.writeRaw('}'); } @Override public void writeStartArray(JsonGenerator jg) throws IOException, JsonGenerationException { if (!_arrayIndenter.isInline()) { ++_nesting; } jg.writeRaw('['); } @Override public void beforeArrayValues(JsonGenerator jg) throws IOException, JsonGenerationException { _arrayIndenter.writeIndentation(jg, _nesting); } /** * Method called after an array value has been completely * output, and before another value is to be output. *

* Default handling (without pretty-printing) will output a single * comma to separate the two. Pretty-printer is * to output a comma as well, but can surround that with other * (white-space) decoration. */ @Override public void writeArrayValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException { jg.writeRaw(','); _arrayIndenter.writeIndentation(jg, _nesting); } @Override public void writeEndArray(JsonGenerator jg, int nrOfValues) throws IOException, JsonGenerationException { if (!_arrayIndenter.isInline()) { --_nesting; } if (nrOfValues > 0) { _arrayIndenter.writeIndentation(jg, _nesting); } else { jg.writeRaw(' '); } jg.writeRaw(']'); } /* /********************************************************** /* Helper classes /********************************************************** */ /** * Dummy implementation that adds no indentation whatsoever */ public static class NopIndenter implements Indenter { public NopIndenter() { } @Override public void writeIndentation(JsonGenerator jg, int level) { } @Override public boolean isInline() { return true; } } /** * This is a very simple indenter that only every adds a * single space for indentation. It is used as the default * indenter for array values. */ public static class FixedSpaceIndenter implements Indenter { public FixedSpaceIndenter() { } @Override public void writeIndentation(JsonGenerator jg, int level) throws IOException, JsonGenerationException { jg.writeRaw(' '); } @Override public boolean isInline() { return true; } } /** * Default linefeed-based indenter uses system-specific linefeeds and * 2 spaces for indentation per level. */ public static class Lf2SpacesIndenter implements Indenter { final static String SYSTEM_LINE_SEPARATOR; static { String lf = null; try { lf = System.getProperty("line.separator"); } catch (Throwable t) { } // access exception? SYSTEM_LINE_SEPARATOR = (lf == null) ? "\n" : lf; } final static int SPACE_COUNT = 64; final static char[] SPACES = new char[SPACE_COUNT]; static { Arrays.fill(SPACES, ' '); } public Lf2SpacesIndenter() { } @Override public boolean isInline() { return false; } @Override public void writeIndentation(JsonGenerator jg, int level) throws IOException, JsonGenerationException { jg.writeRaw(SYSTEM_LINE_SEPARATOR); level += level; // 2 spaces per level while (level > SPACE_COUNT) { // should never happen but... jg.writeRaw(SPACES, 0, SPACE_COUNT); level -= SPACES.length; } jg.writeRaw(SPACES, 0, level); } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/BufferRecycler.java0000644000175000017500000000614511655120726026671 0ustar jamespagejamespagepackage org.codehaus.jackson.util; /** * This is a small utility class, whose main functionality is to allow * simple reuse of raw byte/char buffers. It is usually used through * ThreadLocal member of the owning class pointing to * instance of this class through a SoftReference. The * end result is a low-overhead GC-cleanable recycling: hopefully * ideal for use by stream readers. */ public class BufferRecycler { public final static int DEFAULT_WRITE_CONCAT_BUFFER_LEN = 2000; public enum ByteBufferType { READ_IO_BUFFER(4000) /** * Buffer used for temporarily storing encoded content; used * for example by UTF-8 encoding writer */ ,WRITE_ENCODING_BUFFER(4000) /** * Buffer used for temporarily concatenating output; used for * example when requesting output as byte array. */ ,WRITE_CONCAT_BUFFER(2000) ; private final int size; ByteBufferType(int size) { this.size = size; } } public enum CharBufferType { TOKEN_BUFFER(2000) // Tokenizable input ,CONCAT_BUFFER(2000) // concatenated output ,TEXT_BUFFER(200) // Text content from input ,NAME_COPY_BUFFER(200) // Temporary buffer for getting name characters ; private final int size; CharBufferType(int size) { this.size = size; } } final protected byte[][] _byteBuffers = new byte[ByteBufferType.values().length][]; final protected char[][] _charBuffers = new char[CharBufferType.values().length][]; public BufferRecycler() { } public final byte[] allocByteBuffer(ByteBufferType type) { int ix = type.ordinal(); byte[] buffer = _byteBuffers[ix]; if (buffer == null) { buffer = balloc(type.size); } else { _byteBuffers[ix] = null; } return buffer; } public final void releaseByteBuffer(ByteBufferType type, byte[] buffer) { _byteBuffers[type.ordinal()] = buffer; } public final char[] allocCharBuffer(CharBufferType type) { return allocCharBuffer(type, 0); } public final char[] allocCharBuffer(CharBufferType type, int minSize) { if (type.size > minSize) { minSize = type.size; } int ix = type.ordinal(); char[] buffer = _charBuffers[ix]; if (buffer == null || buffer.length < minSize) { buffer = calloc(minSize); } else { _charBuffers[ix] = null; } return buffer; } public final void releaseCharBuffer(CharBufferType type, char[] buffer) { _charBuffers[type.ordinal()] = buffer; } /* /********************************************************** /* Actual allocations separated for easier debugging/profiling /********************************************************** */ private final byte[] balloc(int size) { return new byte[size]; } private final char[] calloc(int size) { return new char[size]; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/JsonGeneratorDelegate.java0000644000175000017500000001604311655120726030200 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.io.SerializedString; public class JsonGeneratorDelegate extends JsonGenerator { /** * Delegate object that method calls are delegated to. */ protected JsonGenerator delegate; public JsonGeneratorDelegate(JsonGenerator d) { delegate = d; } @Override public void close() throws IOException { delegate.close(); } @Override public void copyCurrentEvent(JsonParser jp) throws IOException, JsonProcessingException { delegate.copyCurrentEvent(jp); } @Override public void copyCurrentStructure(JsonParser jp) throws IOException, JsonProcessingException { delegate.copyCurrentStructure(jp); } @Override public JsonGenerator disable(Feature f) { return delegate.disable(f); } @Override public JsonGenerator enable(Feature f) { return delegate.enable(f); } @Override public void flush() throws IOException { delegate.flush(); } @Override public ObjectCodec getCodec() { return delegate.getCodec(); } @Override public JsonStreamContext getOutputContext() { return delegate.getOutputContext(); } @Override public void setSchema(FormatSchema schema) { delegate.setSchema(schema); } @Override public boolean canUseSchema(FormatSchema schema) { return delegate.canUseSchema(schema); } @Override public Version version() { return delegate.version(); } @Override public Object getOutputTarget() { return delegate.getOutputTarget(); } @Override public boolean isClosed() { return delegate.isClosed(); } @Override public boolean isEnabled(Feature f) { return delegate.isEnabled(f); } @Override public JsonGenerator setCodec(ObjectCodec oc) { delegate.setCodec(oc); return this; } @Override public JsonGenerator useDefaultPrettyPrinter() { delegate.useDefaultPrettyPrinter(); return this; } @Override public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException, JsonGenerationException { delegate.writeBinary(b64variant, data, offset, len); } @Override public void writeBoolean(boolean state) throws IOException, JsonGenerationException { delegate.writeBoolean(state); } @Override public void writeEndArray() throws IOException, JsonGenerationException { delegate.writeEndArray(); } @Override public void writeEndObject() throws IOException, JsonGenerationException { delegate.writeEndObject(); } @Override public void writeFieldName(String name) throws IOException, JsonGenerationException { delegate.writeFieldName(name); } @Override public void writeFieldName(SerializedString name) throws IOException, JsonGenerationException { delegate.writeFieldName(name); } @Override public void writeFieldName(SerializableString name) throws IOException, JsonGenerationException { delegate.writeFieldName(name); } @Override public void writeNull() throws IOException, JsonGenerationException { delegate.writeNull(); } @Override public void writeNumber(int v) throws IOException, JsonGenerationException { delegate.writeNumber(v); } @Override public void writeNumber(long v) throws IOException, JsonGenerationException { delegate.writeNumber(v); } @Override public void writeNumber(BigInteger v) throws IOException, JsonGenerationException { delegate.writeNumber(v); } @Override public void writeNumber(double v) throws IOException, JsonGenerationException { delegate.writeNumber(v); } @Override public void writeNumber(float v) throws IOException, JsonGenerationException { delegate.writeNumber(v); } @Override public void writeNumber(BigDecimal v) throws IOException, JsonGenerationException { delegate.writeNumber(v); } @Override public void writeNumber(String encodedValue) throws IOException, JsonGenerationException, UnsupportedOperationException { delegate.writeNumber(encodedValue); } @Override public void writeObject(Object pojo) throws IOException,JsonProcessingException { delegate.writeObject(pojo); } @Override public void writeRaw(String text) throws IOException, JsonGenerationException { delegate.writeRaw(text); } @Override public void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException { delegate.writeRaw(text, offset, len); } @Override public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException { delegate.writeRaw(text, offset, len); } @Override public void writeRaw(char c) throws IOException, JsonGenerationException { delegate.writeRaw(c); } @Override public void writeRawValue(String text) throws IOException, JsonGenerationException { delegate.writeRawValue(text); } @Override public void writeRawValue(String text, int offset, int len) throws IOException, JsonGenerationException { delegate.writeRawValue(text, offset, len); } @Override public void writeRawValue(char[] text, int offset, int len) throws IOException, JsonGenerationException { delegate.writeRawValue(text, offset, len); } @Override public void writeStartArray() throws IOException, JsonGenerationException { delegate.writeStartArray(); } @Override public void writeStartObject() throws IOException, JsonGenerationException { delegate.writeStartObject(); } @Override public void writeString(String text) throws IOException,JsonGenerationException { delegate.writeString(text); } @Override public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { delegate.writeString(text, offset, len); } @Override public void writeString(SerializableString text) throws IOException, JsonGenerationException { delegate.writeString(text); } @Override public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException { delegate.writeRawUTF8String(text, offset, length); } @Override public void writeUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException { delegate.writeUTF8String(text, offset, length); } @Override public void writeTree(JsonNode rootNode) throws IOException, JsonProcessingException { delegate.writeTree(rootNode); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/JsonParserDelegate.java0000644000175000017500000001405711655120726027511 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; /** * Helper class that implements * delegation pattern for {@link JsonParser}, * to allow for simple overridability of basic parsing functionality. * The idea is that any functionality to be modified can be simply * overridden; and anything else will be delegated by default. * * @since 1.4 */ public class JsonParserDelegate extends JsonParser { /** * Delegate object that method calls are delegated to. */ protected JsonParser delegate; public JsonParserDelegate(JsonParser d) { delegate = d; } /* /********************************************************** /* Public API, configuration /********************************************************** */ @Override public void setCodec(ObjectCodec c) { delegate.setCodec(c); } @Override public ObjectCodec getCodec() { return delegate.getCodec(); } @Override public JsonParser enable(Feature f) { delegate.enable(f); return this; } @Override public JsonParser disable(Feature f) { delegate.disable(f); return this; } @Override public boolean isEnabled(Feature f) { return delegate.isEnabled(f); } @Override public void setSchema(FormatSchema schema) { delegate.setSchema(schema); } @Override public boolean canUseSchema(FormatSchema schema) { return delegate.canUseSchema(schema); } @Override public Version version() { return delegate.version(); } @Override public Object getInputSource() { return delegate.getInputSource(); } /* /********************************************************** /* Closeable impl /********************************************************** */ @Override public void close() throws IOException { delegate.close(); } @Override public boolean isClosed() { return delegate.isClosed(); } /* /********************************************************** /* Public API, token accessors /********************************************************** */ @Override public JsonToken getCurrentToken() { return delegate.getCurrentToken(); } @Override public boolean hasCurrentToken() { return delegate.hasCurrentToken(); } @Override public void clearCurrentToken() { delegate.clearCurrentToken(); } @Override public String getCurrentName() throws IOException, JsonParseException { return delegate.getCurrentName(); } @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); } @Override public JsonToken getLastClearedToken() { return delegate.getLastClearedToken(); } @Override public JsonStreamContext getParsingContext() { return delegate.getParsingContext(); } /* /********************************************************** /* Public API, access to token information, text /********************************************************** */ @Override public String getText() throws IOException, JsonParseException { return delegate.getText(); } @Override public char[] getTextCharacters() throws IOException, JsonParseException { return delegate.getTextCharacters(); } @Override public int getTextLength() throws IOException, JsonParseException { return delegate.getTextLength(); } @Override public int getTextOffset() throws IOException, JsonParseException { return delegate.getTextOffset(); } /* /********************************************************** /* Public API, access to token information, numeric /********************************************************** */ @Override public BigInteger getBigIntegerValue() throws IOException,JsonParseException { return delegate.getBigIntegerValue(); } @Override public byte getByteValue() throws IOException, JsonParseException { return delegate.getByteValue(); } @Override public short getShortValue() throws IOException, JsonParseException { return delegate.getShortValue(); } @Override public BigDecimal getDecimalValue() throws IOException, JsonParseException { return delegate.getDecimalValue(); } @Override public double getDoubleValue() throws IOException, JsonParseException { return delegate.getDoubleValue(); } @Override public float getFloatValue() throws IOException, JsonParseException { return delegate.getFloatValue(); } @Override public int getIntValue() throws IOException, JsonParseException { return delegate.getIntValue(); } @Override public long getLongValue() throws IOException, JsonParseException { return delegate.getLongValue(); } @Override public NumberType getNumberType() throws IOException, JsonParseException { return delegate.getNumberType(); } @Override public Number getNumberValue() throws IOException, JsonParseException { return delegate.getNumberValue(); } @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { return delegate.getBinaryValue(b64variant); } @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); } @Override public JsonToken nextToken() throws IOException, JsonParseException { return delegate.nextToken(); } @Override public JsonParser skipChildren() throws IOException, JsonParseException { delegate.skipChildren(); // NOTE: must NOT delegate this method to delegate, needs to be self-reference for chaining return this; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/TextBuffer.java0000644000175000017500000005227711655120726026054 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.math.BigDecimal; import java.util.ArrayList; import org.codehaus.jackson.io.NumberInput; /** * TextBuffer is a class similar to {@link StringBuffer}, with * following differences: *

    *
  • TextBuffer uses segments character arrays, to avoid having * to do additional array copies when array is not big enough. * This means that only reallocating that is necessary is done only once: * if and when caller * wants to access contents in a linear array (char[], String). *
  • *
  • TextBuffer can also be initialized in "shared mode", in which * it will just act as a wrapper to a single char array managed * by another object (like parser that owns it) *
  • *
  • TextBuffer is not synchronized. *
  • *
*/ public final class TextBuffer { final static char[] NO_CHARS = new char[0]; /** * Let's start with sizable but not huge buffer, will grow as necessary */ final static int MIN_SEGMENT_LEN = 1000; /** * Let's limit maximum segment length to something sensible * like 256k */ final static int MAX_SEGMENT_LEN = 0x40000; /* /********************************************************** /* Configuration: /********************************************************** */ private final BufferRecycler _allocator; /* /********************************************************** /* Shared input buffers /********************************************************** */ /** * Shared input buffer; stored here in case some input can be returned * as is, without being copied to collector's own buffers. Note that * this is read-only for this Object. */ private char[] _inputBuffer; /** * Character offset of first char in input buffer; -1 to indicate * that input buffer currently does not contain any useful char data */ private int _inputStart; private int _inputLen; /* /********************************************************** /* Aggregation segments (when not using input buf) /********************************************************** */ /** * List of segments prior to currently active segment. */ private ArrayList _segments; /** * Flag that indicates whether _seqments is non-empty */ private boolean _hasSegments = false; // // // Currently used segment; not (yet) contained in _seqments /** * Amount of characters in segments in {@link _segments} */ private int _segmentSize; private char[] _currentSegment; /** * Number of characters in currently active (last) segment */ private int _currentSize; /* /********************************************************** /* Caching of results /********************************************************** */ /** * String that will be constructed when the whole contents are * needed; will be temporarily stored in case asked for again. */ private String _resultString; private char[] _resultArray; /* /********************************************************** /* Life-cycle /********************************************************** */ public TextBuffer(BufferRecycler allocator) { _allocator = allocator; } /** * Method called to indicate that the underlying buffers should now * be recycled if they haven't yet been recycled. Although caller * can still use this text buffer, it is not advisable to call this * method if that is likely, since next time a buffer is needed, * buffers need to reallocated. * Note: calling this method automatically also clears contents * of the buffer. */ public void releaseBuffers() { if (_allocator == null) { resetWithEmpty(); } else { if (_currentSegment != null) { // First, let's get rid of all but the largest char array resetWithEmpty(); // And then return that array char[] buf = _currentSegment; _currentSegment = null; _allocator.releaseCharBuffer(BufferRecycler.CharBufferType.TEXT_BUFFER, buf); } } } /** * Method called to clear out any content text buffer may have, and * initializes buffer to use non-shared data. */ public void resetWithEmpty() { _inputStart = -1; // indicates shared buffer not used _currentSize = 0; _inputLen = 0; _inputBuffer = null; _resultString = null; _resultArray = null; // And then reset internal input buffers, if necessary: if (_hasSegments) { clearSegments(); } } /** * Method called to initialize the buffer with a shared copy of data; * this means that buffer will just have pointers to actual data. It * also means that if anything is to be appended to the buffer, it * will first have to unshare it (make a local copy). */ public void resetWithShared(char[] buf, int start, int len) { // First, let's clear intermediate values, if any: _resultString = null; _resultArray = null; // Then let's mark things we need about input buffer _inputBuffer = buf; _inputStart = start; _inputLen = len; // And then reset internal input buffers, if necessary: if (_hasSegments) { clearSegments(); } } public void resetWithCopy(char[] buf, int start, int len) { _inputBuffer = null; _inputStart = -1; // indicates shared buffer not used _inputLen = 0; _resultString = null; _resultArray = null; // And then reset internal input buffers, if necessary: if (_hasSegments) { clearSegments(); } else if (_currentSegment == null) { _currentSegment = findBuffer(len); } _currentSize = _segmentSize = 0; append(buf, start, len); } public void resetWithString(String value) { _inputBuffer = null; _inputStart = -1; _inputLen = 0; _resultString = value; _resultArray = null; if (_hasSegments) { clearSegments(); } _currentSize = 0; } /** * Helper method used to find a buffer to use, ideally one * recycled earlier. */ private final char[] findBuffer(int needed) { if (_allocator != null) { return _allocator.allocCharBuffer(BufferRecycler.CharBufferType.TEXT_BUFFER, needed); } return new char[Math.max(needed, MIN_SEGMENT_LEN)]; } private final void clearSegments() { _hasSegments = false; /* Let's start using _last_ segment from list; for one, it's * the biggest one, and it's also most likely to be cached */ /* 28-Aug-2009, tatu: Actually, the current segment should * be the biggest one, already */ //_currentSegment = _segments.get(_segments.size() - 1); _segments.clear(); _currentSize = _segmentSize = 0; } /* /********************************************************** /* Accessors for implementing public interface /********************************************************** */ /** * @return Number of characters currently stored by this collector */ public int size() { if (_inputStart >= 0) { // shared copy from input buf return _inputLen; } if (_resultArray != null) { return _resultArray.length; } if (_resultString != null) { return _resultString.length(); } // local segmented buffers return _segmentSize + _currentSize; } public int getTextOffset() { /* Only shared input buffer can have non-zero offset; buffer * segments start at 0, and if we have to create a combo buffer, * that too will start from beginning of the buffer */ return (_inputStart >= 0) ? _inputStart : 0; } /** * Method that can be used to check whether textual contents can * be efficiently accessed using {@link #getTextBuffer}. * * @since 1.9 */ public boolean hasTextAsCharacters() { // if we have array in some form, sure if (_inputStart >= 0 || _resultArray != null) { return true; } // not if we have String as value if (_resultString != null) { return false; } return true; } public char[] getTextBuffer() { // Are we just using shared input buffer? if (_inputStart >= 0) { return _inputBuffer; } if (_resultArray != null) { return _resultArray; } if (_resultString != null) { return (_resultArray = _resultString.toCharArray()); } // Nope; but does it fit in just one segment? if (!_hasSegments) { return _currentSegment; } // Nope, need to have/create a non-segmented array and return it return contentsAsArray(); } /* /********************************************************** /* Other accessors: /********************************************************** */ public String contentsAsString() { if (_resultString == null) { // Has array been requested? Can make a shortcut, if so: if (_resultArray != null) { _resultString = new String(_resultArray); } else { // Do we use shared array? if (_inputStart >= 0) { if (_inputLen < 1) { return (_resultString = ""); } _resultString = new String(_inputBuffer, _inputStart, _inputLen); } else { // nope... need to copy // But first, let's see if we have just one buffer int segLen = _segmentSize; int currLen = _currentSize; if (segLen == 0) { // yup _resultString = (currLen == 0) ? "" : new String(_currentSegment, 0, currLen); } else { // no, need to combine StringBuilder sb = new StringBuilder(segLen + currLen); // First stored segments if (_segments != null) { for (int i = 0, len = _segments.size(); i < len; ++i) { char[] curr = _segments.get(i); sb.append(curr, 0, curr.length); } } // And finally, current segment: sb.append(_currentSegment, 0, _currentSize); _resultString = sb.toString(); } } } } return _resultString; } public char[] contentsAsArray() { char[] result = _resultArray; if (result == null) { _resultArray = result = buildResultArray(); } return result; } /** * Convenience method for converting contents of the buffer * into a {@link BigDecimal}. */ public BigDecimal contentsAsDecimal() throws NumberFormatException { // Already got a pre-cut array? if (_resultArray != null) { return new BigDecimal(_resultArray); } // Or a shared buffer? if (_inputStart >= 0) { return new BigDecimal(_inputBuffer, _inputStart, _inputLen); } // Or if not, just a single buffer (the usual case) if (_segmentSize == 0) { return new BigDecimal(_currentSegment, 0, _currentSize); } // If not, let's just get it aggregated... return new BigDecimal(contentsAsArray()); } /** * Convenience method for converting contents of the buffer * into a Double value. */ public double contentsAsDouble() throws NumberFormatException { return NumberInput.parseDouble(contentsAsString()); } /* /********************************************************** /* Public mutators: /********************************************************** */ /** * Method called to make sure that buffer is not using shared input * buffer; if it is, it will copy such contents to private buffer. */ public void ensureNotShared() { if (_inputStart >= 0) { unshare(16); } } public void append(char c) { // Using shared buffer so far? if (_inputStart >= 0) { unshare(16); } _resultString = null; _resultArray = null; // Room in current segment? char[] curr = _currentSegment; if (_currentSize >= curr.length) { expand(1); curr = _currentSegment; } curr[_currentSize++] = c; } public void append(char[] c, int start, int len) { // Can't append to shared buf (sanity check) if (_inputStart >= 0) { unshare(len); } _resultString = null; _resultArray = null; // Room in current segment? char[] curr = _currentSegment; int max = curr.length - _currentSize; if (max >= len) { System.arraycopy(c, start, curr, _currentSize, len); _currentSize += len; } else { // No room for all, need to copy part(s): if (max > 0) { System.arraycopy(c, start, curr, _currentSize, max); start += max; len -= max; } // And then allocate new segment; we are guaranteed to now // have enough room in segment. expand(len); // note: curr != _currentSegment after this System.arraycopy(c, start, _currentSegment, 0, len); _currentSize = len; } } public void append(String str, int offset, int len) { // Can't append to shared buf (sanity check) if (_inputStart >= 0) { unshare(len); } _resultString = null; _resultArray = null; // Room in current segment? char[] curr = _currentSegment; int max = curr.length - _currentSize; if (max >= len) { str.getChars(offset, offset+len, curr, _currentSize); _currentSize += len; } else { // No room for all, need to copy part(s): if (max > 0) { str.getChars(offset, offset+max, curr, _currentSize); len -= max; offset += max; } /* And then allocate new segment; we are guaranteed to now * have enough room in segment. */ expand(len); str.getChars(offset, offset+len, _currentSegment, 0); _currentSize = len; } } /* /********************************************************** /* Raw access, for high-performance use: /********************************************************** */ public char[] getCurrentSegment() { /* Since the intention of the caller is to directly add stuff into * buffers, we should NOT have anything in shared buffer... ie. may * need to unshare contents. */ if (_inputStart >= 0) { unshare(1); } else { char[] curr = _currentSegment; if (curr == null) { _currentSegment = findBuffer(0); } else if (_currentSize >= curr.length) { // Plus, we better have room for at least one more char expand(1); } } return _currentSegment; } public final char[] emptyAndGetCurrentSegment() { // inlined 'resetWithEmpty()' _inputStart = -1; // indicates shared buffer not used _currentSize = 0; _inputLen = 0; _inputBuffer = null; _resultString = null; _resultArray = null; // And then reset internal input buffers, if necessary: if (_hasSegments) { clearSegments(); } char[] curr = _currentSegment; if (curr == null) { _currentSegment = curr = findBuffer(0); } return curr; } public int getCurrentSegmentSize() { return _currentSize; } public void setCurrentLength(int len) { _currentSize = len; } public char[] finishCurrentSegment() { if (_segments == null) { _segments = new ArrayList(); } _hasSegments = true; _segments.add(_currentSegment); int oldLen = _currentSegment.length; _segmentSize += oldLen; // Let's grow segments by 50% int newLen = Math.min(oldLen + (oldLen >> 1), MAX_SEGMENT_LEN); char[] curr = _charArray(newLen); _currentSize = 0; _currentSegment = curr; return curr; } /** * Method called to expand size of the current segment, to * accomodate for more contiguous content. Usually only * used when parsing tokens like names. */ public char[] expandCurrentSegment() { char[] curr = _currentSegment; // Let's grow by 50% int len = curr.length; // Must grow by at least 1 char, no matter what int newLen = (len == MAX_SEGMENT_LEN) ? (MAX_SEGMENT_LEN + 1) : Math.min(MAX_SEGMENT_LEN, len + (len >> 1)); _currentSegment = _charArray(newLen); System.arraycopy(curr, 0, _currentSegment, 0, len); return _currentSegment; } /* /********************************************************** /* Standard methods: /********************************************************** */ /** * Note: calling this method may not be as efficient as calling * {@link #contentsAsString}, since it's not guaranteed that resulting * String is cached. */ @Override public String toString() { return contentsAsString(); } /* /********************************************************** /* Internal methods: /********************************************************** */ /** * Method called if/when we need to append content when we have been * initialized to use shared buffer. */ private void unshare(int needExtra) { int sharedLen = _inputLen; _inputLen = 0; char[] inputBuf = _inputBuffer; _inputBuffer = null; int start = _inputStart; _inputStart = -1; // Is buffer big enough, or do we need to reallocate? int needed = sharedLen+needExtra; if (_currentSegment == null || needed > _currentSegment.length) { _currentSegment = findBuffer(needed); } if (sharedLen > 0) { System.arraycopy(inputBuf, start, _currentSegment, 0, sharedLen); } _segmentSize = 0; _currentSize = sharedLen; } /** * Method called when current segment is full, to allocate new * segment. */ private void expand(int minNewSegmentSize) { // First, let's move current segment to segment list: if (_segments == null) { _segments = new ArrayList(); } char[] curr = _currentSegment; _hasSegments = true; _segments.add(curr); _segmentSize += curr.length; int oldLen = curr.length; // Let's grow segments by 50% minimum int sizeAddition = oldLen >> 1; if (sizeAddition < minNewSegmentSize) { sizeAddition = minNewSegmentSize; } curr = _charArray(Math.min(MAX_SEGMENT_LEN, oldLen + sizeAddition)); _currentSize = 0; _currentSegment = curr; } private char[] buildResultArray() { if (_resultString != null) { // Can take a shortcut... return _resultString.toCharArray(); } char[] result; // Do we use shared array? if (_inputStart >= 0) { if (_inputLen < 1) { return NO_CHARS; } result = _charArray(_inputLen); System.arraycopy(_inputBuffer, _inputStart, result, 0, _inputLen); } else { // nope int size = size(); if (size < 1) { return NO_CHARS; } int offset = 0; result = _charArray(size); if (_segments != null) { for (int i = 0, len = _segments.size(); i < len; ++i) { char[] curr = (char[]) _segments.get(i); int currLen = curr.length; System.arraycopy(curr, 0, result, offset, currLen); offset += currLen; } } System.arraycopy(_currentSegment, 0, result, offset, _currentSize); } return result; } private final char[] _charArray(int len) { return new char[len]; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/TokenBuffer.java0000644000175000017500000012655611655120726026212 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.impl.JsonParserMinimalBase; import org.codehaus.jackson.impl.JsonReadContext; import org.codehaus.jackson.impl.JsonWriteContext; import org.codehaus.jackson.io.SerializedString; /** * Utility class used for efficient storage of {@link JsonToken} * sequences, needed for temporary buffering. * Space efficient for different sequence lengths (especially so for smaller * ones; but not significantly less efficient for larger), highly efficient * for linear iteration and appending. Implemented as segmented/chunked * linked list of tokens; only modifications are via appends. * * @since 1.5 */ public class TokenBuffer /* Won't use JsonGeneratorBase, to minimize overhead for validity * checking */ extends JsonGenerator { protected final static int DEFAULT_PARSER_FEATURES = JsonParser.Feature.collectDefaults(); /* /********************************************************** /* Configuration /********************************************************** */ /** * Object codec to use for stream-based object * conversion through parser/generator interfaces. If null, * such methods can not be used. */ protected ObjectCodec _objectCodec; /** * Bit flag composed of bits that indicate which * {@link org.codehaus.jackson.JsonGenerator.Feature}s * are enabled. *

* NOTE: most features have no effect on this class */ protected int _generatorFeatures; protected boolean _closed; /* /********************************************************** /* Token buffering state /********************************************************** */ /** * First segment, for contents this buffer has */ protected Segment _first; /** * Last segment of this buffer, one that is used * for appending more tokens */ protected Segment _last; /** * Offset within last segment, */ protected int _appendOffset; /* /********************************************************** /* Output state /********************************************************** */ protected JsonWriteContext _writeContext; /* /********************************************************** /* Life-cycle /********************************************************** */ /** * @param codec Object codec to use for stream-based object * conversion through parser/generator interfaces. If null, * such methods can not be used. */ public TokenBuffer(ObjectCodec codec) { _objectCodec = codec; _generatorFeatures = DEFAULT_PARSER_FEATURES; _writeContext = JsonWriteContext.createRootContext(); // at first we have just one segment _first = _last = new Segment(); _appendOffset = 0; } /** * Method used to create a {@link JsonParser} that can read contents * stored in this buffer. Will use default _objectCodec for * object conversions. *

* Note: instances are not synchronized, that is, they are not thread-safe * if there are concurrent appends to the underlying buffer. * * @return Parser that can be used for reading contents stored in this buffer */ public JsonParser asParser() { return asParser(_objectCodec); } /** * Method used to create a {@link JsonParser} that can read contents * stored in this buffer. *

* Note: instances are not synchronized, that is, they are not thread-safe * if there are concurrent appends to the underlying buffer. * * @param codec Object codec to use for stream-based object * conversion through parser/generator interfaces. If null, * such methods can not be used. * * @return Parser that can be used for reading contents stored in this buffer */ public JsonParser asParser(ObjectCodec codec) { return new Parser(_first, codec); } /** * @param src Parser to use for accessing source information * like location, configured codec */ public JsonParser asParser(JsonParser src) { Parser p = new Parser(_first, src.getCodec()); p.setLocation(src.getTokenLocation()); return p; } /* /********************************************************** /* Other custom methods not needed for implementing interfaces /********************************************************** */ /** * Helper method that will write all contents of this buffer * using given {@link JsonGenerator}. *

* Note: this method would be enough to implement * JsonSerializer for TokenBuffer type; * but we can not have upwards * references (from core to mapper package); and as such we also * can not take second argument. */ public void serialize(JsonGenerator jgen) throws IOException, JsonGenerationException { Segment segment = _first; int ptr = -1; while (true) { if (++ptr >= Segment.TOKENS_PER_SEGMENT) { ptr = 0; segment = segment.next(); if (segment == null) break; } JsonToken t = segment.type(ptr); if (t == null) break; // Note: copied from 'copyCurrentEvent'... switch (t) { case START_OBJECT: jgen.writeStartObject(); break; case END_OBJECT: jgen.writeEndObject(); break; case START_ARRAY: jgen.writeStartArray(); break; case END_ARRAY: jgen.writeEndArray(); break; case FIELD_NAME: { // 13-Dec-2010, tatu: Maybe we should start using different type tokens to reduce casting? Object ob = segment.get(ptr); if (ob instanceof SerializableString) { jgen.writeFieldName((SerializableString) ob); } else { jgen.writeFieldName((String) ob); } } break; case VALUE_STRING: { Object ob = segment.get(ptr); if (ob instanceof SerializableString) { jgen.writeString((SerializableString) ob); } else { jgen.writeString((String) ob); } } break; case VALUE_NUMBER_INT: { Number n = (Number) segment.get(ptr); if (n instanceof BigInteger) { jgen.writeNumber((BigInteger) n); } else if (n instanceof Long) { jgen.writeNumber(n.longValue()); } else { jgen.writeNumber(n.intValue()); } } break; case VALUE_NUMBER_FLOAT: { Object n = segment.get(ptr); if (n instanceof BigDecimal) { jgen.writeNumber((BigDecimal) n); } else if (n instanceof Float) { jgen.writeNumber(((Float) n).floatValue()); } else if (n instanceof Double) { jgen.writeNumber(((Double) n).doubleValue()); } else if (n == null) { jgen.writeNull(); } else if (n instanceof String) { jgen.writeNumber((String) n); } else { throw new JsonGenerationException("Unrecognized value type for VALUE_NUMBER_FLOAT: "+n.getClass().getName()+", can not serialize"); } } break; case VALUE_TRUE: jgen.writeBoolean(true); break; case VALUE_FALSE: jgen.writeBoolean(false); break; case VALUE_NULL: jgen.writeNull(); break; case VALUE_EMBEDDED_OBJECT: jgen.writeObject(segment.get(ptr)); break; default: throw new RuntimeException("Internal error: should never end up through this code path"); } } } @Override public String toString() { // Let's print up to 100 first tokens... final int MAX_COUNT = 100; StringBuilder sb = new StringBuilder(); sb.append("[TokenBuffer: "); JsonParser jp = asParser(); int count = 0; while (true) { JsonToken t; try { t = jp.nextToken(); } catch (IOException ioe) { // should never occur throw new IllegalStateException(ioe); } if (t == null) break; if (count < MAX_COUNT) { if (count > 0) { sb.append(", "); } sb.append(t.toString()); } ++count; } if (count >= MAX_COUNT) { sb.append(" ... (truncated ").append(count-MAX_COUNT).append(" entries)"); } sb.append(']'); return sb.toString(); } /* /********************************************************** /* JsonGenerator implementation: configuration /********************************************************** */ @Override public JsonGenerator enable(Feature f) { _generatorFeatures |= f.getMask(); return this; } @Override public JsonGenerator disable(Feature f) { _generatorFeatures &= ~f.getMask(); return this; } //public JsonGenerator configure(Feature f, boolean state) { } @Override public boolean isEnabled(Feature f) { return (_generatorFeatures & f.getMask()) != 0; } @Override public JsonGenerator useDefaultPrettyPrinter() { // No-op: we don't indent return this; } @Override public JsonGenerator setCodec(ObjectCodec oc) { _objectCodec = oc; return this; } @Override public ObjectCodec getCodec() { return _objectCodec; } @Override public final JsonWriteContext getOutputContext() { return _writeContext; } /* /********************************************************** /* JsonGenerator implementation: low-level output handling /********************************************************** */ @Override public void flush() throws IOException { /* NOP */ } @Override public void close() throws IOException { _closed = true; } @Override public boolean isClosed() { return _closed; } /* /********************************************************** /* JsonGenerator implementation: write methods, structural /********************************************************** */ @Override public final void writeStartArray() throws IOException, JsonGenerationException { _append(JsonToken.START_ARRAY); _writeContext = _writeContext.createChildArrayContext(); } @Override public final void writeEndArray() throws IOException, JsonGenerationException { _append(JsonToken.END_ARRAY); // Let's allow unbalanced tho... i.e. not run out of root level, ever JsonWriteContext c = _writeContext.getParent(); if (c != null) { _writeContext = c; } } @Override public final void writeStartObject() throws IOException, JsonGenerationException { _append(JsonToken.START_OBJECT); _writeContext = _writeContext.createChildObjectContext(); } @Override public final void writeEndObject() throws IOException, JsonGenerationException { _append(JsonToken.END_OBJECT); // Let's allow unbalanced tho... i.e. not run out of root level, ever JsonWriteContext c = _writeContext.getParent(); if (c != null) { _writeContext = c; } } @Override public final void writeFieldName(String name) throws IOException, JsonGenerationException { _append(JsonToken.FIELD_NAME, name); _writeContext.writeFieldName(name); } @Override public void writeFieldName(SerializableString name) throws IOException, JsonGenerationException { _append(JsonToken.FIELD_NAME, name); _writeContext.writeFieldName(name.getValue()); } @Override public void writeFieldName(SerializedString name) throws IOException, JsonGenerationException { _append(JsonToken.FIELD_NAME, name); _writeContext.writeFieldName(name.getValue()); } /* /********************************************************** /* JsonGenerator implementation: write methods, textual /********************************************************** */ @Override public void writeString(String text) throws IOException,JsonGenerationException { if (text == null) { writeNull(); } else { _append(JsonToken.VALUE_STRING, text); } } @Override public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException { writeString(new String(text, offset, len)); } @Override public void writeString(SerializableString text) throws IOException, JsonGenerationException { if (text == null) { writeNull(); } else { _append(JsonToken.VALUE_STRING, text); } } @Override public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException { // could add support for buffering if we really want it... _reportUnsupportedOperation(); } @Override public void writeUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException { // could add support for buffering if we really want it... _reportUnsupportedOperation(); } @Override public void writeRaw(String text) throws IOException, JsonGenerationException { _reportUnsupportedOperation(); } @Override public void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException { _reportUnsupportedOperation(); } @Override public void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException { _reportUnsupportedOperation(); } @Override public void writeRaw(char c) throws IOException, JsonGenerationException { _reportUnsupportedOperation(); } @Override public void writeRawValue(String text) throws IOException, JsonGenerationException { _reportUnsupportedOperation(); } @Override public void writeRawValue(String text, int offset, int len) throws IOException, JsonGenerationException { _reportUnsupportedOperation(); } @Override public void writeRawValue(char[] text, int offset, int len) throws IOException, JsonGenerationException { _reportUnsupportedOperation(); } /* /********************************************************** /* JsonGenerator implementation: write methods, primitive types /********************************************************** */ @Override public void writeNumber(int i) throws IOException, JsonGenerationException { _append(JsonToken.VALUE_NUMBER_INT, Integer.valueOf(i)); } @Override public void writeNumber(long l) throws IOException, JsonGenerationException { _append(JsonToken.VALUE_NUMBER_INT, Long.valueOf(l)); } @Override public void writeNumber(double d) throws IOException,JsonGenerationException { _append(JsonToken.VALUE_NUMBER_FLOAT, Double.valueOf(d)); } @Override public void writeNumber(float f) throws IOException, JsonGenerationException { _append(JsonToken.VALUE_NUMBER_FLOAT, Float.valueOf(f)); } @Override public void writeNumber(BigDecimal dec) throws IOException,JsonGenerationException { if (dec == null) { writeNull(); } else { _append(JsonToken.VALUE_NUMBER_FLOAT, dec); } } @Override public void writeNumber(BigInteger v) throws IOException, JsonGenerationException { if (v == null) { writeNull(); } else { _append(JsonToken.VALUE_NUMBER_INT, v); } } @Override public void writeNumber(String encodedValue) throws IOException, JsonGenerationException { /* 03-Dec-2010, tatu: related to [JACKSON-423], should try to keep as numeric * identity as long as possible */ _append(JsonToken.VALUE_NUMBER_FLOAT, encodedValue); } @Override public void writeBoolean(boolean state) throws IOException,JsonGenerationException { _append(state ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE); } @Override public void writeNull() throws IOException, JsonGenerationException { _append(JsonToken.VALUE_NULL); } /* /*********************************************************** /* JsonGenerator implementation: write methods for POJOs/trees /*********************************************************** */ @Override public void writeObject(Object value) throws IOException, JsonProcessingException { // embedded means that no conversions should be done... _append(JsonToken.VALUE_EMBEDDED_OBJECT, value); } @Override public void writeTree(JsonNode rootNode) throws IOException, JsonProcessingException { /* 31-Dec-2009, tatu: no need to convert trees either is there? * (note: may need to re-evaluate at some point) */ _append(JsonToken.VALUE_EMBEDDED_OBJECT, rootNode); } /* /*********************************************************** /* JsonGenerator implementation; binary /*********************************************************** */ @Override public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException, JsonGenerationException { /* 31-Dec-2009, tatu: can do this using multiple alternatives; but for * now, let's try to limit number of conversions. * The only (?) tricky thing is that of whether to preserve variant, * seems pointless, so let's not worry about it unless there's some * compelling reason to. */ byte[] copy = new byte[len]; System.arraycopy(data, offset, copy, 0, len); writeObject(copy); } /* /********************************************************** /* JsonGenerator implementation; pass-through copy /********************************************************** */ @Override public void copyCurrentEvent(JsonParser jp) throws IOException, JsonProcessingException { switch (jp.getCurrentToken()) { case START_OBJECT: writeStartObject(); break; case END_OBJECT: writeEndObject(); break; case START_ARRAY: writeStartArray(); break; case END_ARRAY: writeEndArray(); break; case FIELD_NAME: writeFieldName(jp.getCurrentName()); break; case VALUE_STRING: if (jp.hasTextCharacters()) { writeString(jp.getTextCharacters(), jp.getTextOffset(), jp.getTextLength()); } else { writeString(jp.getText()); } break; case VALUE_NUMBER_INT: switch (jp.getNumberType()) { case INT: writeNumber(jp.getIntValue()); break; case BIG_INTEGER: writeNumber(jp.getBigIntegerValue()); break; default: writeNumber(jp.getLongValue()); } break; case VALUE_NUMBER_FLOAT: switch (jp.getNumberType()) { case BIG_DECIMAL: writeNumber(jp.getDecimalValue()); break; case FLOAT: writeNumber(jp.getFloatValue()); break; default: writeNumber(jp.getDoubleValue()); } break; case VALUE_TRUE: writeBoolean(true); break; case VALUE_FALSE: writeBoolean(false); break; case VALUE_NULL: writeNull(); break; case VALUE_EMBEDDED_OBJECT: writeObject(jp.getEmbeddedObject()); break; default: throw new RuntimeException("Internal error: should never end up through this code path"); } } @Override public void copyCurrentStructure(JsonParser jp) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); // Let's handle field-name separately first if (t == JsonToken.FIELD_NAME) { writeFieldName(jp.getCurrentName()); t = jp.nextToken(); // fall-through to copy the associated value } switch (t) { case START_ARRAY: writeStartArray(); while (jp.nextToken() != JsonToken.END_ARRAY) { copyCurrentStructure(jp); } writeEndArray(); break; case START_OBJECT: writeStartObject(); while (jp.nextToken() != JsonToken.END_OBJECT) { copyCurrentStructure(jp); } writeEndObject(); break; default: // others are simple: copyCurrentEvent(jp); } } /* /********************************************************** /* Internal methods /********************************************************** */ protected final void _append(JsonToken type) { Segment next = _last.append(_appendOffset, type); if (next == null) { ++_appendOffset; } else { _last = next; _appendOffset = 1; // since we added first at 0 } } protected final void _append(JsonToken type, Object value) { Segment next = _last.append(_appendOffset, type, value); if (next == null) { ++_appendOffset; } else { _last = next; _appendOffset = 1; } } protected void _reportUnsupportedOperation() { throw new UnsupportedOperationException("Called operation not supported for TokenBuffer"); } /* /********************************************************** /* Supporting classes /********************************************************** */ protected final static class Parser extends JsonParserMinimalBase { protected ObjectCodec _codec; /* /********************************************************** /* Parsing state /********************************************************** */ /** * Currently active segment */ protected Segment _segment; /** * Pointer to current token within current segment */ protected int _segmentPtr; /** * Information about parser context, context in which * the next token is to be parsed (root, array, object). */ protected JsonReadContext _parsingContext; protected boolean _closed; protected transient ByteArrayBuilder _byteBuilder; protected JsonLocation _location = null; /* /********************************************************** /* Construction, init /********************************************************** */ public Parser(Segment firstSeg, ObjectCodec codec) { super(0); _segment = firstSeg; _segmentPtr = -1; // not yet read _codec = codec; _parsingContext = JsonReadContext.createRootContext(-1, -1); } public void setLocation(JsonLocation l) { _location = l; } @Override public ObjectCodec getCodec() { return _codec; } @Override public void setCodec(ObjectCodec c) { _codec = c; } /* /********************************************************** /* Extended API beyond JsonParser /********************************************************** */ public JsonToken peekNextToken() throws IOException, JsonParseException { // closed? nothing more to peek, either if (_closed) return null; Segment seg = _segment; int ptr = _segmentPtr+1; if (ptr >= Segment.TOKENS_PER_SEGMENT) { ptr = 0; seg = (seg == null) ? null : seg.next(); } return (seg == null) ? null : seg.type(ptr); } /* /********************************************************** /* Closeable implementation /********************************************************** */ @Override public void close() throws IOException { if (!_closed) { _closed = true; } } /* /********************************************************** /* Public API, traversal /********************************************************** */ @Override public JsonToken nextToken() throws IOException, JsonParseException { // If we are closed, nothing more to do if (_closed || (_segment == null)) return null; // Ok, then: any more tokens? if (++_segmentPtr >= Segment.TOKENS_PER_SEGMENT) { _segmentPtr = 0; _segment = _segment.next(); if (_segment == null) { return null; } } _currToken = _segment.type(_segmentPtr); // Field name? Need to update context if (_currToken == JsonToken.FIELD_NAME) { Object ob = _currentObject(); String name = (ob instanceof String) ? ((String) ob) : ob.toString(); _parsingContext.setCurrentName(name); } else if (_currToken == JsonToken.START_OBJECT) { _parsingContext = _parsingContext.createChildObjectContext(-1, -1); } else if (_currToken == JsonToken.START_ARRAY) { _parsingContext = _parsingContext.createChildArrayContext(-1, -1); } else if (_currToken == JsonToken.END_OBJECT || _currToken == JsonToken.END_ARRAY) { // Closing JSON Object/Array? Close matching context _parsingContext = _parsingContext.getParent(); // but allow unbalanced cases too (more close markers) if (_parsingContext == null) { _parsingContext = JsonReadContext.createRootContext(-1, -1); } } return _currToken; } @Override public boolean isClosed() { return _closed; } /* /********************************************************** /* Public API, token accessors /********************************************************** */ @Override public JsonStreamContext getParsingContext() { return _parsingContext; } @Override public JsonLocation getTokenLocation() { return getCurrentLocation(); } @Override public JsonLocation getCurrentLocation() { return (_location == null) ? JsonLocation.NA : _location; } @Override public String getCurrentName() { return _parsingContext.getCurrentName(); } /* /********************************************************** /* Public API, access to token information, text /********************************************************** */ @Override public String getText() { // common cases first: if (_currToken == JsonToken.VALUE_STRING || _currToken == JsonToken.FIELD_NAME) { Object ob = _currentObject(); if (ob instanceof String) { return (String) ob; } return (ob == null) ? null : ob.toString(); } if (_currToken == null) { return null; } switch (_currToken) { case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: Object ob = _currentObject(); return (ob == null) ? null : ob.toString(); } return _currToken.asString(); } @Override public char[] getTextCharacters() { String str = getText(); return (str == null) ? null : str.toCharArray(); } @Override public int getTextLength() { String str = getText(); return (str == null) ? 0 : str.length(); } @Override public int getTextOffset() { return 0; } @Override public boolean hasTextCharacters() { // We never have raw buffer available, so: return false; } /* /********************************************************** /* Public API, access to token information, numeric /********************************************************** */ @Override public BigInteger getBigIntegerValue() throws IOException, JsonParseException { Number n = getNumberValue(); if (n instanceof BigInteger) { return (BigInteger) n; } switch (getNumberType()) { case BIG_DECIMAL: return ((BigDecimal) n).toBigInteger(); } // int/long is simple, but let's also just truncate float/double: return BigInteger.valueOf(n.longValue()); } @Override public BigDecimal getDecimalValue() throws IOException, JsonParseException { Number n = getNumberValue(); if (n instanceof BigDecimal) { return (BigDecimal) n; } switch (getNumberType()) { case INT: case LONG: return BigDecimal.valueOf(n.longValue()); case BIG_INTEGER: return new BigDecimal((BigInteger) n); } // float or double return BigDecimal.valueOf(n.doubleValue()); } @Override public double getDoubleValue() throws IOException, JsonParseException { return getNumberValue().doubleValue(); } @Override public float getFloatValue() throws IOException, JsonParseException { return getNumberValue().floatValue(); } @Override public int getIntValue() throws IOException, JsonParseException { // optimize common case: if (_currToken == JsonToken.VALUE_NUMBER_INT) { return ((Number) _currentObject()).intValue(); } return getNumberValue().intValue(); } @Override public long getLongValue() throws IOException, JsonParseException { return getNumberValue().longValue(); } @Override public NumberType getNumberType() throws IOException, JsonParseException { Number n = getNumberValue(); if (n instanceof Integer) return NumberType.INT; if (n instanceof Long) return NumberType.LONG; if (n instanceof Double) return NumberType.DOUBLE; if (n instanceof BigDecimal) return NumberType.BIG_DECIMAL; if (n instanceof Float) return NumberType.FLOAT; if (n instanceof BigInteger) return NumberType.BIG_INTEGER; return null; } @Override public final Number getNumberValue() throws IOException, JsonParseException { _checkIsNumber(); return (Number) _currentObject(); } /* /********************************************************** /* Public API, access to token information, other /********************************************************** */ @Override public Object getEmbeddedObject() { if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) { return _currentObject(); } return null; } @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { // First: maybe we some special types? if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) { // Embedded byte array would work nicely... Object ob = _currentObject(); if (ob instanceof byte[]) { return (byte[]) ob; } // fall through to error case } if (_currToken != JsonToken.VALUE_STRING) { throw _constructError("Current token ("+_currToken+") not VALUE_STRING (or VALUE_EMBEDDED_OBJECT with byte[]), can not access as binary"); } final String str = getText(); if (str == null) { return null; } ByteArrayBuilder builder = _byteBuilder; if (builder == null) { _byteBuilder = builder = new ByteArrayBuilder(100); } _decodeBase64(str, builder, b64variant); return builder.toByteArray(); } /* /********************************************************** /* Internal methods /********************************************************** */ protected void _decodeBase64(String str, ByteArrayBuilder builder, Base64Variant b64variant) throws IOException, JsonParseException { int ptr = 0; int len = str.length(); main_loop: while (ptr < len) { // first, we'll skip preceding white space, if any char ch; do { ch = str.charAt(ptr++); if (ptr >= len) { break main_loop; } } while (ch <= INT_SPACE); int bits = b64variant.decodeBase64Char(ch); if (bits < 0) { _reportInvalidBase64(b64variant, ch, 0, null); } int decodedData = bits; // then second base64 char; can't get padding yet, nor ws if (ptr >= len) { _reportBase64EOF(); } ch = str.charAt(ptr++); bits = b64variant.decodeBase64Char(ch); if (bits < 0) { _reportInvalidBase64(b64variant, ch, 1, null); } decodedData = (decodedData << 6) | bits; // third base64 char; can be padding, but not ws if (ptr >= len) { // but as per [JACKSON-631] can be end-of-input, iff not using padding if (!b64variant.usesPadding()) { decodedData >>= 4; builder.append(decodedData); break; } _reportBase64EOF(); } ch = str.charAt(ptr++); bits = b64variant.decodeBase64Char(ch); // First branch: can get padding (-> 1 byte) if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { _reportInvalidBase64(b64variant, ch, 2, null); } // Ok, must get padding if (ptr >= len) { _reportBase64EOF(); } ch = str.charAt(ptr++); if (!b64variant.usesPaddingChar(ch)) { _reportInvalidBase64(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'"); } // Got 12 bits, only need 8, need to shift decodedData >>= 4; builder.append(decodedData); continue; } // Nope, 2 or 3 bytes decodedData = (decodedData << 6) | bits; // fourth and last base64 char; can be padding, but not ws if (ptr >= len) { // but as per [JACKSON-631] can be end-of-input, iff not using padding if (!b64variant.usesPadding()) { decodedData >>= 2; builder.appendTwoBytes(decodedData); break; } _reportBase64EOF(); } ch = str.charAt(ptr++); bits = b64variant.decodeBase64Char(ch); if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { _reportInvalidBase64(b64variant, ch, 3, null); } decodedData >>= 2; builder.appendTwoBytes(decodedData); } else { // otherwise, our triple is now complete decodedData = (decodedData << 6) | bits; builder.appendThreeBytes(decodedData); } } } protected final Object _currentObject() { return _segment.get(_segmentPtr); } protected final void _checkIsNumber() throws JsonParseException { if (_currToken == null || !_currToken.isNumeric()) { throw _constructError("Current token ("+_currToken+") not numeric, can not use numeric value accessors"); } } /** * @param bindex Relative index within base64 character unit; between 0 * and 3 (as unit has exactly 4 characters) */ protected void _reportInvalidBase64(Base64Variant b64variant, char ch, int bindex, String msg) throws JsonParseException { String base; if (ch <= INT_SPACE) { base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units"; } else if (b64variant.usesPaddingChar(ch)) { base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character"; } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) { // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level) base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content"; } else { base = "Illegal character '"+ch+"' (code 0x"+Integer.toHexString(ch)+") in base64 content"; } if (msg != null) { base = base + ": " + msg; } throw _constructError(base); } protected void _reportBase64EOF() throws JsonParseException { throw _constructError("Unexpected end-of-String in base64 content"); } @Override protected void _handleEOF() throws JsonParseException { _throwInternal(); } } /** * Individual segment of TokenBuffer that can store up to 16 tokens * (limited by 4 bits per token type marker requirement). * Current implementation uses fixed length array; could alternatively * use 16 distinct fields and switch statement (slightly more efficient * storage, slightly slower access) */ protected final static class Segment { public final static int TOKENS_PER_SEGMENT = 16; /** * Static array used for fast conversion between token markers and * matching {@link JsonToken} instances */ private final static JsonToken[] TOKEN_TYPES_BY_INDEX; static { // ... here we know that there are <= 16 values in JsonToken enum TOKEN_TYPES_BY_INDEX = new JsonToken[16]; JsonToken[] t = JsonToken.values(); System.arraycopy(t, 1, TOKEN_TYPES_BY_INDEX, 1, Math.min(15, t.length - 1)); } // // // Linking protected Segment _next; // // // State /** * Bit field used to store types of buffered tokens; 4 bits per token. * Value 0 is reserved for "not in use" */ protected long _tokenTypes; // Actual tokens protected final Object[] _tokens = new Object[TOKENS_PER_SEGMENT]; public Segment() { } // // // Accessors public JsonToken type(int index) { long l = _tokenTypes; if (index > 0) { l >>= (index << 2); } int ix = ((int) l) & 0xF; return TOKEN_TYPES_BY_INDEX[ix]; } public Object get(int index) { return _tokens[index]; } public Segment next() { return _next; } // // // Mutators public Segment append(int index, JsonToken tokenType) { if (index < TOKENS_PER_SEGMENT) { set(index, tokenType); return null; } _next = new Segment(); _next.set(0, tokenType); return _next; } public Segment append(int index, JsonToken tokenType, Object value) { if (index < TOKENS_PER_SEGMENT) { set(index, tokenType, value); return null; } _next = new Segment(); _next.set(0, tokenType, value); return _next; } public void set(int index, JsonToken tokenType) { long typeCode = tokenType.ordinal(); /* Assumption here is that there are no overwrites, just appends; * and so no masking is needed */ if (index > 0) { typeCode <<= (index << 2); } _tokenTypes |= typeCode; } public void set(int index, JsonToken tokenType, Object value) { _tokens[index] = value; long typeCode = tokenType.ordinal(); /* Assumption here is that there are no overwrites, just appends; * and so no masking is needed */ if (index > 0) { typeCode <<= (index << 2); } _tokenTypes |= typeCode; } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/util/CharTypes.java0000644000175000017500000001732511655120726025673 0ustar jamespagejamespagepackage org.codehaus.jackson.util; import java.util.Arrays; import org.codehaus.jackson.io.CharacterEscapes; public final class CharTypes { private final static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray(); private final static byte[] HEX_BYTES; static { int len = HEX_CHARS.length; HEX_BYTES = new byte[len]; for (int i = 0; i < len; ++i) { HEX_BYTES[i] = (byte) HEX_CHARS[i]; } } /** * Lookup table used for determining which input characters * need special handling when contained in text segment. */ final static int[] sInputCodes; static { /* 96 would do for most cases (backslash is ascii 94) * but if we want to do lookups by raw bytes it's better * to have full table */ int[] table = new int[256]; // Control chars and non-space white space are not allowed unquoted for (int i = 0; i < 32; ++i) { table[i] = -1; } // And then string end and quote markers are special too table['"'] = 1; table['\\'] = 1; sInputCodes = table; } /** * Additionally we can combine UTF-8 decoding info into similar * data table. */ final static int[] sInputCodesUtf8; static { int[] table = new int[sInputCodes.length]; System.arraycopy(sInputCodes, 0, table, 0, sInputCodes.length); for (int c = 128; c < 256; ++c) { int code; // We'll add number of bytes needed for decoding if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF) code = 2; } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF) code = 3; } else if ((c & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all... code = 4; } else { // And -1 seems like a good "universal" error marker... code = -1; } table[c] = code; } sInputCodesUtf8 = table; } /** * To support non-default (and -standard) unquoted field names mode, * need to have alternate checking. * Basically this is list of 8-bit ASCII characters that are legal * as part of Javascript identifier * * @since 1.2 */ final static int[] sInputCodesJsNames; static { int[] table = new int[256]; // Default is "not a name char", mark ones that are Arrays.fill(table, -1); // Assume rules with JS same as Java (change if/as needed) for (int i = 33; i < 256; ++i) { if (Character.isJavaIdentifierPart((char) i)) { table[i] = 0; } } /* As per [JACKSON-267], '@', '#' and '*' are also to be accepted as well. * And '-' (for hyphenated names); and '+' for sake of symmetricity... */ table['@'] = 0; table['#'] = 0; table['*'] = 0; table['-'] = 0; table['+'] = 0; sInputCodesJsNames = table; } /** * This table is similar to Latin-1, except that it marks all "high-bit" * code as ok. They will be validated at a later point, when decoding * name */ final static int[] sInputCodesUtf8JsNames; static { int[] table = new int[256]; // start with 8-bit JS names System.arraycopy(sInputCodesJsNames, 0, table, 0, sInputCodesJsNames.length); Arrays.fill(table, 128, 128, 0); sInputCodesUtf8JsNames = table; } /** * Decoding table used to quickly determine characters that are * relevant within comment content */ final static int[] sInputCodesComment = new int[256]; static { // but first: let's start with UTF-8 multi-byte markers: System.arraycopy(sInputCodesUtf8, 128, sInputCodesComment, 128, 128); // default (0) means "ok" (skip); -1 invalid, others marked by char itself Arrays.fill(sInputCodesComment, 0, 32, -1); // invalid white space sInputCodesComment['\t'] = 0; // tab is still fine sInputCodesComment['\n'] = '\n'; // lf/cr need to be observed, ends cpp comment sInputCodesComment['\r'] = '\r'; sInputCodesComment['*'] = '*'; // end marker for c-style comments } /** * Lookup table used for determining which output characters in * 7-bit ASCII range need to be quoted. */ final static int[] sOutputEscapes128; static { int[] table = new int[128]; // Control chars need generic escape sequence for (int i = 0; i < 32; ++i) { // 04-Mar-2011, tatu: Used to use "-(i + 1)", replaced with constants table[i] = CharacterEscapes.ESCAPE_STANDARD; } /* Others (and some within that range too) have explicit shorter * sequences */ table['"'] = '"'; table['\\'] = '\\'; // Escaping of slash is optional, so let's not add it table[0x08] = 'b'; table[0x09] = 't'; table[0x0C] = 'f'; table[0x0A] = 'n'; table[0x0D] = 'r'; sOutputEscapes128 = table; } /** * Lookup table for the first 128 Unicode characters (7-bit ASCII) * range. For actual hex digits, contains corresponding value; * for others -1. */ final static int[] sHexValues = new int[128]; static { Arrays.fill(sHexValues, -1); for (int i = 0; i < 10; ++i) { sHexValues['0' + i] = i; } for (int i = 0; i < 6; ++i) { sHexValues['a' + i] = 10 + i; sHexValues['A' + i] = 10 + i; } } public final static int[] getInputCodeLatin1() { return sInputCodes; } public final static int[] getInputCodeUtf8() { return sInputCodesUtf8; } public final static int[] getInputCodeLatin1JsNames() { return sInputCodesJsNames; } public final static int[] getInputCodeUtf8JsNames() { return sInputCodesUtf8JsNames; } public final static int[] getInputCodeComment() { return sInputCodesComment; } /** * Accessor for getting a read-only encoding table for first 128 Unicode * code points (single-byte UTF-8 characters). * Value of 0 means "no escaping"; other positive values that value is character * to use after backslash; and negative values that generic (backslash - u) * escaping is to be used. */ public final static int[] get7BitOutputEscapes() { return sOutputEscapes128; } public static int charToHex(int ch) { return (ch > 127) ? -1 : sHexValues[ch]; } public static void appendQuoted(StringBuilder sb, String content) { final int[] escCodes = sOutputEscapes128; int escLen = escCodes.length; for (int i = 0, len = content.length(); i < len; ++i) { char c = content.charAt(i); if (c >= escLen || escCodes[c] == 0) { sb.append(c); continue; } sb.append('\\'); int escCode = escCodes[c]; if (escCode < 0) { // generic quoting (hex value) // We know that it has to fit in just 2 hex chars sb.append('u'); sb.append('0'); sb.append('0'); int value = -(escCode + 1); sb.append(HEX_CHARS[value >> 4]); sb.append(HEX_CHARS[value & 0xF]); } else { // "named", i.e. prepend with slash sb.append((char) escCode); } } } /** * @since 1.6 */ public static char[] copyHexChars() { return (char[]) HEX_CHARS.clone(); } /** * @since 1.6 */ public static byte[] copyHexBytes() { return (byte[]) HEX_BYTES.clone(); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/PrettyPrinter.java0000644000175000017500000001354611655120726025650 0ustar jamespagejamespagepackage org.codehaus.jackson; import java.io.IOException; /** * Interface for objects that implement pretty printer functionality, such * as indentation. * Pretty printers are used to add white space in output JSON content, * to make results more human readable. Usually this means things like adding * linefeeds and indentation. */ public interface PrettyPrinter { /* /********************************************************** /* First methods that act both as events, and expect /* output for correct functioning (i.e something gets /* output even when not pretty-printing) /********************************************************** */ // // // Root-level handling: /** * Method called after a root-level value has been completely * output, and before another value is to be output. *

* Default * handling (without pretty-printing) will output a space, to * allow values to be parsed correctly. Pretty-printer is * to output some other suitable and nice-looking separator * (tab(s), space(s), linefeed(s) or any combination thereof). */ public void writeRootValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException; // // Object handling /** * Method called when an Object value is to be output, before * any fields are output. *

* Default handling (without pretty-printing) will output * the opening curly bracket. * Pretty-printer is * to output a curly bracket as well, but can surround that * with other (white-space) decoration. */ public void writeStartObject(JsonGenerator jg) throws IOException, JsonGenerationException; /** * Method called after an Object value has been completely output * (minus closing curly bracket). *

* Default handling (without pretty-printing) will output * the closing curly bracket. * Pretty-printer is * to output a curly bracket as well, but can surround that * with other (white-space) decoration. * * @param nrOfEntries Number of direct members of the array that * have been output */ public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException, JsonGenerationException; /** * Method called after an object entry (field:value) has been completely * output, and before another value is to be output. *

* Default handling (without pretty-printing) will output a single * comma to separate the two. Pretty-printer is * to output a comma as well, but can surround that with other * (white-space) decoration. */ public void writeObjectEntrySeparator(JsonGenerator jg) throws IOException, JsonGenerationException; /** * Method called after an object field has been output, but * before the value is output. *

* Default handling (without pretty-printing) will output a single * colon to separate the two. Pretty-printer is * to output a colon as well, but can surround that with other * (white-space) decoration. */ public void writeObjectFieldValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException; // // // Array handling /** * Method called when an Array value is to be output, before * any member/child values are output. *

* Default handling (without pretty-printing) will output * the opening bracket. * Pretty-printer is * to output a bracket as well, but can surround that * with other (white-space) decoration. */ public void writeStartArray(JsonGenerator jg) throws IOException, JsonGenerationException; /** * Method called after an Array value has been completely output * (minus closing bracket). *

* Default handling (without pretty-printing) will output * the closing bracket. * Pretty-printer is * to output a bracket as well, but can surround that * with other (white-space) decoration. * * @param nrOfValues Number of direct members of the array that * have been output */ public void writeEndArray(JsonGenerator jg, int nrOfValues) throws IOException, JsonGenerationException; /** * Method called after an array value has been completely * output, and before another value is to be output. *

* Default handling (without pretty-printing) will output a single * comma to separate the two. Pretty-printer is * to output a comma as well, but can surround that with other * (white-space) decoration. */ public void writeArrayValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException; /* /********************************************************** /* Then events that by default do not produce any output /* but that are often overridden to add white space /* in pretty-printing mode /********************************************************** */ /** * Method called after array start marker has been output, * and right before the first value is to be output. * It is not called for arrays with no values. *

* Default handling does not output anything, but pretty-printer * is free to add any white space decoration. */ public void beforeArrayValues(JsonGenerator jg) throws IOException, JsonGenerationException; /** * Method called after object start marker has been output, * and right before the field name of the first entry is * to be output. * It is not called for objects without entries. *

* Default handling does not output anything, but pretty-printer * is free to add any white space decoration. */ public void beforeObjectEntries(JsonGenerator jg) throws IOException, JsonGenerationException; } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonStreamContext.java0000644000175000017500000000766411655120726026453 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson; /** * Shared base class for streaming processing contexts used during * reading and writing of Json content using Streaming API. * This context is also exposed to applications: * context object can be used by applications to get an idea of * relative position of the parser/generator within json content * being processed. This allows for some contextual processing: for * example, output within Array context can differ from that of * Object context. */ public abstract class JsonStreamContext { // // // Type constants used internally protected final static int TYPE_ROOT = 0; protected final static int TYPE_ARRAY = 1; protected final static int TYPE_OBJECT = 2; protected int _type; /** * Index of the currently processed entry. Starts with -1 to signal * that no entries have been started, and gets advanced each * time a new entry is started, either by encountering an expected * separator, or with new values if no separators are expected * (the case for root context). */ protected int _index; /* /********************************************************** /* Life-cycle /********************************************************** */ protected JsonStreamContext() { } /* /********************************************************** /* Public API, accessors /********************************************************** */ /** * Accessor for finding parent context of this context; will * return null for root context. */ public abstract JsonStreamContext getParent(); /** * Method that returns true if this context is an Array context; * that is, content is being read from or written to a Json Array. */ public final boolean inArray() { return _type == TYPE_ARRAY; } /** * Method that returns true if this context is a Root context; * that is, content is being read from or written to without * enclosing array or object structure. */ public final boolean inRoot() { return _type == TYPE_ROOT; } /** * Method that returns true if this context is an Object context; * that is, content is being read from or written to a Json Object. */ public final boolean inObject() { return _type == TYPE_OBJECT; } /** * Method for accessing simple type description of current context; * either ROOT (for root-level values), OBJECT (for field names and * values of JSON Objects) or ARRAY (for values of JSON Arrays) */ public final String getTypeDesc() { switch (_type) { case TYPE_ROOT: return "ROOT"; case TYPE_ARRAY: return "ARRAY"; case TYPE_OBJECT: return "OBJECT"; } return "?"; } /** * @return Number of entries that are complete and started. */ public final int getEntryCount() { return _index + 1; } /** * @return Index of the currently processed entry, if any */ public final int getCurrentIndex() { return (_index < 0) ? 0 : _index; } /** * Method for accessing name associated with the current location. * Non-null for FIELD_NAME and value events that directly * follow field names; null for root level and array values. */ public abstract String getCurrentName(); } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonProcessingException.java0000644000175000017500000000372111655120726027634 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Intermediate base class for all problems encountered when * processing (parsing, generating) JSON content * that are not pure I/O problems. * Regular {@link java.io.IOException}s will be passed through as is. * Sub-class of {@link java.io.IOException} for convenience. */ public class JsonProcessingException extends java.io.IOException { final static long serialVersionUID = 123; // Stupid eclipse... protected JsonLocation mLocation; protected JsonProcessingException(String msg, JsonLocation loc, Throwable rootCause) { /* Argh. IOException(Throwable,String) is only available starting * with JDK 1.6... */ super(msg); if (rootCause != null) { initCause(rootCause); } mLocation = loc; } protected JsonProcessingException(String msg) { super(msg); } protected JsonProcessingException(String msg, JsonLocation loc) { this(msg, loc, null); } protected JsonProcessingException(String msg, Throwable rootCause) { this(msg, null, rootCause); } protected JsonProcessingException(Throwable rootCause) { this(null, null, rootCause); } public JsonLocation getLocation() { return mLocation; } /** * Default method overridden so that we can add location information */ @Override public String getMessage() { String msg = super.getMessage(); if (msg == null) { msg = "N/A"; } JsonLocation loc = getLocation(); if (loc != null) { StringBuilder sb = new StringBuilder(); sb.append(msg); sb.append('\n'); sb.append(" at "); sb.append(loc.toString()); return sb.toString(); } return msg; } @Override public String toString() { return getClass().getName()+": "+getMessage(); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/package-info.java0000644000175000017500000000216211655120726025331 0ustar jamespagejamespage/** * Main public API classes of the core streaming JSON * processor: most importantly {@link org.codehaus.jackson.JsonFactory} * used for constructing * JSON parser ({@link org.codehaus.jackson.JsonParser}) * and generator * ({@link org.codehaus.jackson.JsonParser}) * instances. *

* Public API of the higher-level mapping interfaces ("Mapping API") * is found from * under {@link org.codehaus.jackson.map} and not included here, * except for following base interfaces: *

    *
  • {@link org.codehaus.jackson.JsonNode} is included *within Streaming API to support integration of the Tree Model *(which is based on JsonNode) with the basic *parsers and generators (iff using mapping-supporting factory: which *is part of Mapping API, not core) *
  • *
  • {@link org.codehaus.jackson.ObjectCodec} is included so that * reference to the object capable of serializing/deserializing * Objects to/from JSON (usually, {@link org.codehaus.jackson.map.ObjectMapper}) * can be exposed, without adding direct dependency to implementation. *
  • *
* */ package org.codehaus.jackson; jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonNode.java0000644000175000017500000007633111655120726024535 0ustar jamespagejamespagepackage org.codehaus.jackson; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.*; /** * Base class for all JSON nodes, which form the basis of JSON * Tree Model that Jackson implements. * One way to think of these nodes is to consider them * similar to DOM nodes in XML DOM trees. *

* As a general design rule, most accessors ("getters") are included * in this base class, to allow for traversing structure without * type casts. Most mutators, however, need to be accessed through * specific sub-classes (such as org.codehaus.jackson.node.ObjectNode * and org.codehaus.jackson.node.ArrayNode). * This seems sensible because proper type * information is generally available when building or modifying * trees, but less often when reading a tree (newly built from * parsed JSON content). *

* Actual concrete sub-classes can be found from package * {@link org.codehaus.jackson.node}, which is in 'mapper' jar * (whereas this class is in 'core' jar, since it is declared as * nominal type for operations in {@link ObjectCodec}) */ public abstract class JsonNode implements Iterable { protected final static List NO_NODES = Collections.emptyList(); protected final static List NO_STRINGS = Collections.emptyList(); protected JsonNode() { } /* /********************************************************** /* Public API, type introspection /********************************************************** */ // // First high-level division between values, containers and "missing" /** * Method that returns true for all value nodes: ones that * are not containers, and that do not represent "missing" nodes * in the path. Such value nodes represent String, Number, Boolean * and null values from JSON. *

* Note: one and only one of methods {@link #isValueNode}, * {@link #isContainerNode} and {@link #isMissingNode} ever * returns true for any given node. */ public boolean isValueNode() { return false; } /** * Method that returns true for container nodes: Arrays and Objects. *

* Note: one and only one of methods {@link #isValueNode}, * {@link #isContainerNode} and {@link #isMissingNode} ever * returns true for any given node. */ public boolean isContainerNode() { return false; } /** * Method that returns true for "virtual" nodes which represent * missing entries constructed by path accessor methods when * there is no actual node matching given criteria. *

* Note: one and only one of methods {@link #isValueNode}, * {@link #isContainerNode} and {@link #isMissingNode} ever * returns true for any given node. */ public boolean isMissingNode() { return false; } // // Then more specific type introspection // // (along with defaults to be overridden) /** * @return True if this node represents Json Array */ public boolean isArray() { return false; } /** * @return True if this node represents Json Object */ public boolean isObject() { return false; } /** * Method that can be used to check if the node is a wrapper * for a POJO ("Plain Old Java Object" aka "bean". * Returns true only for * instances of {@link org.codehaus.jackson.node.POJONode}. * * @return True if this node wraps a POJO */ public boolean isPojo() { return false; } /** * @return True if this node represents a numeric Json * value */ public boolean isNumber() { return false; } /** * @return True if this node represents an integral (integer) * numeric Json value */ public boolean isIntegralNumber() { return false; } /** * @return True if this node represents a non-integral * numeric Json value */ public boolean isFloatingPointNumber() { return false; } /** * @return True if this node represents an integral * numeric Json value that withs in Java int value space */ public boolean isInt() { return false; } /** * @return True if this node represents an integral * numeric Json value that fits in Java long value space * (but not int value space, i.e. {@link #isInt} returns false) */ public boolean isLong() { return false; } public boolean isDouble() { return false; } public boolean isBigDecimal() { return false; } public boolean isBigInteger() { return false; } public boolean isTextual() { return false; } /** * Method that can be used to check if this node was created from * Json boolean value (literals "true" and "false"). */ public boolean isBoolean() { return false; } /** * Method that can be used to check if this node was created from * Json liternal null value. */ public boolean isNull() { return false; } /** * Method that can be used to check if this node represents * binary data (Base64 encoded). Although this will be externally * written as Json String value, {@link #isTextual} will * return false if this method returns true. * * @return True if this node represents base64 encoded binary data */ public boolean isBinary() { return false; } /** * Method that can be used for efficient type detection * when using stream abstraction for traversing nodes. * Will return the first {@link JsonToken} that equivalent * stream event would produce (for most nodes there is just * one token but for structured/container types multiple) * * @since 1.3 */ public abstract JsonToken asToken(); /** * If this node is a numeric type (as per {@link #isNumber}), * returns native type that node uses to store the numeric * value. */ public abstract JsonParser.NumberType getNumberType(); /* /********************************************************** /* Public API, straight value access /********************************************************** */ /** * Method to use for accessing String values. * Does NOT do any conversions for non-String value nodes; * for non-String values (ones for which {@link #isTextual} returns * false) null will be returned. * For String values, null is never returned (but empty Strings may be) * * @return Textual value this node contains, iff it is a textual * json node (comes from Json String value entry) */ public String getTextValue() { return null; } /** * Method to use for accessing binary content of binary nodes (nodes * for which {@link #isBinary} returns true); or for Text Nodes * (ones for which {@link #getTextValue} returns non-null value), * to read decoded base64 data. * For other types of nodes, returns null. * * @return Binary data this node contains, iff it is a binary * node; null otherwise */ public byte[] getBinaryValue() throws IOException { return null; } /** * Method to use for accessing JSON boolean values (value * literals 'true' and 'false'). * For other types, always returns false. * * @return Textual value this node contains, iff it is a textual * json node (comes from Json String value entry) */ public boolean getBooleanValue() { return false; } /** * Returns numeric value for this node, if and only if * this node is numeric ({@link #isNumber} returns true); otherwise * returns null * * @return Number value this node contains, if any (null for non-number * nodes). */ public Number getNumberValue() { return null; } /** * Returns integer value for this node, if and only if * this node is numeric ({@link #isNumber} returns true). For other * types returns 0. * For floating-point numbers, value is truncated using default * Java coercion, similar to how cast from double to int operates. * * @return Integer value this node contains, if any; 0 for non-number * nodes. */ public int getIntValue() { return 0; } public long getLongValue() { return 0L; } public double getDoubleValue() { return 0.0; } public BigDecimal getDecimalValue() { return BigDecimal.ZERO; } public BigInteger getBigIntegerValue() { return BigInteger.ZERO; } /** * Method for accessing value of the specified element of * an array node. For other nodes, null is always returned. *

* For array nodes, index specifies * exact location within array and allows for efficient iteration * over child elements (underlying storage is guaranteed to * be efficiently indexable, i.e. has random-access to elements). * If index is less than 0, or equal-or-greater than * node.size(), null is returned; no exception is * thrown for any index. * * @return Node that represent value of the specified element, * if this node is an array and has specified element. * Null otherwise. */ public JsonNode get(int index) { return null; } /** * Method for accessing value of the specified field of * an object node. If this node is not an object (or it * does not have a value for specified field name), or * if there is no field with such name, null is returned. * * @return Node that represent value of the specified field, * if this node is an object and has value for the specified * field. Null otherwise. */ public JsonNode get(String fieldName) { return null; } /* /********************************************************** /* Public API, value access with conversion(s)/coercion(s) /********************************************************** */ /** * Method that will return valid String representation of * the container value, if the node is a value node * (method {@link #isValueNode} returns true), otherwise * empty String. * * @since 1.9 (replaces getValueAsText) */ public abstract String asText(); /** * Method that will try to convert value of this node to a Java int. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * default value of 0 will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsInt) */ public int asInt() { return asInt(0); } /** * Method that will try to convert value of this node to a Java int. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsInt) */ public int asInt(int defaultValue) { return defaultValue; } /** * Method that will try to convert value of this node to a Java long. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an long (including structured types * like Objects and Arrays), * default value of 0 will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsLong) */ public long asLong() { return asLong(0L); } /** * Method that will try to convert value of this node to a Java long. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an long (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsLong) */ public long asLong(long defaultValue) { return defaultValue; } /** * Method that will try to convert value of this node to a Java double. * Numbers are coerced using default Java rules; booleans convert to 0.0 (false) * and 1.0 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * default value of 0.0 will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsDouble) */ public double asDouble() { return asDouble(0.0); } /** * Method that will try to convert value of this node to a Java double. * Numbers are coerced using default Java rules; booleans convert to 0.0 (false) * and 1.0 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsLong) */ public double asDouble(double defaultValue) { return defaultValue; } /** * Method that will try to convert value of this node to a Java boolean. * JSON booleans map naturally; integer numbers other than 0 map to true, and * 0 maps to false * and Strings 'true' and 'false' map to corresponding values. *

* If representation can not be converted to a boolean value (including structured types * like Objects and Arrays), * default value of false will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsBoolean) */ public boolean asBoolean() { return asBoolean(false); } /** * Method that will try to convert value of this node to a Java boolean. * JSON booleans map naturally; integer numbers other than 0 map to true, and * 0 maps to false * and Strings 'true' and 'false' map to corresponding values. *

* If representation can not be converted to a boolean value (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.9 (replaces getValueAsBoolean) */ public boolean asBoolean(boolean defaultValue) { return defaultValue; } /* /********************************************************** /* Public API, value access with conversion(s)/coercion(s) /********************************************************** */ /** * Method that will return valid String representation of * the container value, if the node is a value node * (method {@link #isValueNode} returns true), otherwise null. *

* Note: to serialize nodes of any type, you should call * {@link #toString} instead. * * @deprecated Since 1.9, use {@link #asText} instead */ @Deprecated public String getValueAsText() { return asText(); } /** * Method that will try to convert value of this node to a Java int. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * default value of 0 will be returned; no exceptions are thrown. * * @since 1.6 * * @deprecated Since 1.9, use {@link #asInt} instead */ @Deprecated public int getValueAsInt() { return asInt(0); } /** * Method that will try to convert value of this node to a Java int. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.6 * * @deprecated Since 1.9, use {@link #asInt} instead */ @Deprecated public int getValueAsInt(int defaultValue) { return asInt(defaultValue); } /** * Method that will try to convert value of this node to a Java long. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an long (including structured types * like Objects and Arrays), * default value of 0 will be returned; no exceptions are thrown. * * @since 1.6 * * @deprecated Since 1.9, use {@link #asLong} instead */ @Deprecated public long getValueAsLong() { return asLong(0L); } /** * Method that will try to convert value of this node to a Java long. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an long (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.6 * * @deprecated Since 1.9, use {@link #asLong} instead */ @Deprecated public long getValueAsLong(long defaultValue) { return asLong(defaultValue); } /** * Method that will try to convert value of this node to a Java double. * Numbers are coerced using default Java rules; booleans convert to 0.0 (false) * and 1.0 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * default value of 0.0 will be returned; no exceptions are thrown. * * @since 1.6 * * @deprecated Since 1.9, use {@link #asDouble} instead */ @Deprecated public double getValueAsDouble() { return asDouble(0.0); } /** * Method that will try to convert value of this node to a Java double. * Numbers are coerced using default Java rules; booleans convert to 0.0 (false) * and 1.0 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.6 * * @deprecated Since 1.9, use {@link #asDouble} instead */ @Deprecated public double getValueAsDouble(double defaultValue) { return asDouble(defaultValue); } /** * Method that will try to convert value of this node to a Java boolean. * JSON booleans map naturally; integer numbers other than 0 map to true, and * 0 maps to false * and Strings 'true' and 'false' map to corresponding values. *

* If representation can not be converted to a boolean value (including structured types * like Objects and Arrays), * default value of false will be returned; no exceptions are thrown. * * @since 1.7 * * @deprecated Since 1.9, use {@link #asBoolean} instead */ @Deprecated public boolean getValueAsBoolean() { return asBoolean(false); } /** * Method that will try to convert value of this node to a Java boolean. * JSON booleans map naturally; integer numbers other than 0 map to true, and * 0 maps to false * and Strings 'true' and 'false' map to corresponding values. *

* If representation can not be converted to a boolean value (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.7 * * @deprecated Since 1.9, use {@link #asBoolean} instead */ @Deprecated public boolean getValueAsBoolean(boolean defaultValue) { return asBoolean(defaultValue); } /* /********************************************************** /* Public API, value find / existence check methods /********************************************************** */ /** * Method that allows checking whether this node is JSON Object node * and contains value for specified property. If this is the case * (including properties with explicit null values), returns true; * otherwise returns false. *

* This method is equivalent to: *

     *   node.get(fieldName) != null
     *
* (since return value of get() is node, not value node contains) * * @param fieldName Name of element to check * * @return True if this node is a JSON Object node, and has a property * entry with specified name (with any value, including null value) * * @since 1.6 */ public boolean has(String fieldName) { return get(fieldName) != null; } /** * Method that allows checking whether this node is JSON Array node * and contains a value for specified index * If this is the case * (including case of specified indexing having null as value), returns true; * otherwise returns false. *

* Note: array element indexes are 0-based. *

* This method is equivalent to: *

     *   node.get(index) != null
     *
* * @param index Index to check * * @return True if this node is a JSON Object node, and has a property * entry with specified name (with any value, including null value) * * @since 1.6 */ public boolean has(int index) { return get(index) != null; } /** * Method for finding a JSON Object field with specified name in this * node or its child nodes, and returning value it has. * If no matching field is found in this node or its descendants, returns null. * * @param fieldName Name of field to look for * * @return Value of first matching node found, if any; null if none * * @since 1.6 */ public abstract JsonNode findValue(String fieldName); /** * Method for finding JSON Object fields with specified name, and returning * found ones as a List. Note that sub-tree search ends if a field is found, * so possible children of result nodes are not included. * If no matching fields are found in this node or its descendants, returns * an empty List. * * @param fieldName Name of field to look for * * @since 1.6 */ public final List findValues(String fieldName) { List result = findValues(fieldName, null); if (result == null) { return Collections.emptyList(); } return result; } /** * Similar to {@link #findValues}, but will additionally convert * values into Strings, calling {@link #getValueAsText}. * * @since 1.6 */ public final List findValuesAsText(String fieldName) { List result = findValuesAsText(fieldName, null); if (result == null) { return Collections.emptyList(); } return result; } /** * Method similar to {@link #findValue}, but that will return a * "missing node" instead of null if no field is found. Missing node * is a specific kind of node for which {@link #isMissingNode} * returns true; and all value access methods return empty or * missing value. * * @param fieldName Name of field to look for * * @return Value of first matching node found; or if not found, a * "missing node" (non-null instance that has no value) * * @since 1.6 */ public abstract JsonNode findPath(String fieldName); /** * Method for finding a JSON Object that contains specified field, * within this node or its descendants. * If no matching field is found in this node or its descendants, returns null. * * @param fieldName Name of field to look for * * @return Value of first matching node found, if any; null if none * * @since 1.6 */ public abstract JsonNode findParent(String fieldName); /** * Method for finding a JSON Object that contains specified field, * within this node or its descendants. * If no matching field is found in this node or its descendants, returns null. * * @param fieldName Name of field to look for * * @return Value of first matching node found, if any; null if none * * @since 1.6 */ public final List findParents(String fieldName) { List result = findParents(fieldName, null); if (result == null) { return Collections.emptyList(); } return result; } public abstract List findValues(String fieldName, List foundSoFar); public abstract List findValuesAsText(String fieldName, List foundSoFar); public abstract List findParents(String fieldName, List foundSoFar); /* /********************************************************** /* Public API, container access /********************************************************** */ /** * Method that returns number of child nodes this node contains: * for Array nodes, number of child elements, for Object nodes, * number of fields, and for all other nodes 0. * * @return For non-container nodes returns 0; for arrays number of * contained elements, and for objects number of fields. */ public int size() { return 0; } /** * Same as calling {@link #getElements}; implemented so that * convenience "for-each" loop can be used for looping over elements * of JSON Array constructs. */ @Override public final Iterator iterator() { return getElements(); } /** * Method for accessing all value nodes of this Node, iff * this node is a JSON Array or Object node. In case of Object node, * field names (keys) are not included, only values. * For other types of nodes, returns empty iterator. */ public Iterator getElements() { return NO_NODES.iterator(); } /** * Method for accessing names of all fields for this Node, iff * this node is a JSON Object node. */ public Iterator getFieldNames() { return NO_STRINGS.iterator(); } /** * @return Iterator that can be used to traverse all key/value pairs for * object nodes; empty iterator (no contents) for other types * * @since 1.8 (although existed in ObjectNode since 1.0 or so) */ public Iterator> getFields() { Collection> coll = Collections.emptyList(); return coll.iterator(); } /* /********************************************************** /* Public API, path handling /********************************************************** */ /** * This method is similar to {@link #get(String)}, except * that instead of returning null if no such value exists (due * to this node not being an object, or object not having value * for the specified field), * a "missing node" (node that returns true for * {@link #isMissingNode}) will be returned. This allows for * convenient and safe chained access via path calls. */ public abstract JsonNode path(String fieldName); /** * Alias of {@link #path(String)}. * * @deprecated Use {@link #path(String)} instead */ @Deprecated public final JsonNode getPath(String fieldName) { return path(fieldName); } /** * This method is similar to {@link #get(int)}, except * that instead of returning null if no such element exists (due * to index being out of range, or this node not being an array), * a "missing node" (node that returns true for * {@link #isMissingNode}) will be returned. This allows for * convenient and safe chained access via path calls. */ public abstract JsonNode path(int index); /** * Alias of {@link #path(int)}. * * @deprecated Use {@link #path(int)} instead */ @Deprecated public final JsonNode getPath(int index) { return path(index); } /** * Method that can be called on object nodes, to access a property * that has object value; or if no such property exists, to create and * return such object node. * If node method is called on is not Object node, * or if property exists and has value that is not object node, * {@link UnsupportedOperationException} is thrown * * @since 1.8 */ public JsonNode with(String propertyName) { throw new UnsupportedOperationException("JsonNode not of type ObjectNode (but " +getClass().getName()+"), can not call with() on it"); } /* /********************************************************** /* Public API: converting to/from Streaming API /********************************************************** */ /** * Method for constructing a {@link JsonParser} instance for * iterating over contents of the tree that this * node is root of. * Functionally equivalent to first serializing tree using * {@link ObjectCodec} and then re-parsing but * more efficient. */ public abstract JsonParser traverse(); /* /********************************************************** /* Overridden standard methods /********************************************************** */ /** *

* Note: marked as abstract to ensure all implementation * classes define it properly. */ @Override public abstract String toString(); /** * Equality for node objects is defined as full (deep) value * equality. This means that it is possible to compare complete * JSON trees for equality by comparing equality of root nodes. *

* Note: marked as abstract to ensure all implementation * classes define it properly and not rely on definition * from {@link java.lang.Object}. */ @Override public abstract boolean equals(Object o); } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonParser.java0000644000175000017500000014747211655120726025111 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Iterator; import org.codehaus.jackson.type.TypeReference; /** * Base class that defines public API for reading JSON content. * Instances are created using factory methods of * a {@link JsonFactory} instance. * * @author Tatu Saloranta */ public abstract class JsonParser implements Closeable, Versioned { private final static int MIN_BYTE_I = (int) Byte.MIN_VALUE; private final static int MAX_BYTE_I = (int) Byte.MAX_VALUE; private final static int MIN_SHORT_I = (int) Short.MIN_VALUE; private final static int MAX_SHORT_I = (int) Short.MAX_VALUE; /** * Enumeration of possible "native" (optimal) types that can be * used for numbers. */ public enum NumberType { INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL }; /** * Enumeration that defines all togglable features for parsers. */ public enum Feature { // // // Low-level I/O handling features: /** * Feature that determines whether parser will automatically * close underlying input source that is NOT owned by the * parser. If disabled, calling application has to separately * close the underlying {@link InputStream} and {@link Reader} * instances used to create the parser. If enabled, parser * will handle closing, as long as parser itself gets closed: * this happens when end-of-input is encountered, or parser * is closed by a call to {@link JsonParser#close}. *

* Feature is enabled by default. */ AUTO_CLOSE_SOURCE(true), // // // Support for non-standard data format constructs /** * Feature that determines whether parser will allow use * of Java/C++ style comments (both '/'+'*' and * '//' varieties) within parsed content or not. *

* Since JSON specification does not mention comments as legal * construct, * this is a non-standard feature; however, in the wild * this is extensively used. As such, feature is * disabled by default for parsers and must be * explicitly enabled (via factory or parser instance). *

* This feature can be changed for parser instances. */ ALLOW_COMMENTS(false), /** * Feature that determines whether parser will allow use * of unquoted field names (which is allowed by Javascript, * but not by JSON specification). *

* Since JSON specification requires use of double quotes for * field names, * this is a non-standard feature, and as such disabled by * default. *

* This feature can be changed for parser instances. * * @since 1.2 */ ALLOW_UNQUOTED_FIELD_NAMES(false), /** * Feature that determines whether parser will allow use * of single quotes (apostrophe, character '\'') for * quoting Strings (names and String values). If so, * this is in addition to other acceptabl markers. * but not by JSON specification). *

* Since JSON specification requires use of double quotes for * field names, * this is a non-standard feature, and as such disabled by * default. *

* This feature can be changed for parser instances. * * @since 1.3 */ ALLOW_SINGLE_QUOTES(false), /** * Feature that determines whether parser will allow * JSON Strings to contain unquoted control characters * (ASCII characters with value less than 32, including * tab and line feed characters) or not. * If feature is set false, an exception is thrown if such a * character is encountered. *

* Since JSON specification requires quoting for all control characters, * this is a non-standard feature, and as such disabled by default. *

* This feature can be changed for parser instances. * * @since 1.4 */ ALLOW_UNQUOTED_CONTROL_CHARS(false), /** * Feature that can be enabled to accept quoting of all character * using backslash qooting mechanism: if not enabled, only characters * that are explicitly listed by JSON specification can be thus * escaped (see JSON spec for small list of these characters) *

* Since JSON specification requires quoting for all control characters, * this is a non-standard feature, and as such disabled by default. *

* This feature can be changed for parser instances. * * @since 1.6 */ ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false), /** * Feature that determines whether parser will allow * JSON integral numbers to start with additional (ignorable) * zeroes (like: 000001). If enabled, no exception is thrown, and extra * nulls are silently ignored (and not included in textual representation * exposed via {@link JsonParser#getText}). *

* Since JSON specification does not allow leading zeroes, * this is a non-standard feature, and as such disabled by default. *

* This feature can be changed for parser instances. * * @since 1.8 */ ALLOW_NUMERIC_LEADING_ZEROS(false), /** * Feature that allows parser to recognize set of * "Not-a-Number" (NaN) tokens as legal floating number * values (similar to how many other data formats and * programming language source code allows it). * Specific subset contains values that * XML Schema * (see section 3.2.4.1, Lexical Representation) * allows (tokens are quoted contents, not including quotes): *

    *
  • "INF" (for positive infinity), as well as alias of "Infinity" *
  • "-INF" (for negative infinity), alias "-Infinity" *
  • "NaN" (for other not-a-numbers, like result of division by zero) *
*/ ALLOW_NON_NUMERIC_NUMBERS(false), // // // Controlling canonicalization (interning etc) /** * Feature that determines whether JSON object field names are * to be canonicalized using {@link String#intern} or not: * if enabled, all field names will be intern()ed (and caller * can count on this being true for all such names); if disabled, * no intern()ing is done. There may still be basic * canonicalization (that is, same String will be used to represent * all identical object property names for a single document). *

* Note: this setting only has effect if * {@link #CANONICALIZE_FIELD_NAMES} is true -- otherwise no * canonicalization of any sort is done. * * @since 1.3 */ INTERN_FIELD_NAMES(true), /** * Feature that determines whether JSON object field names are * to be canonicalized (details of how canonicalization is done * then further specified by * {@link #INTERN_FIELD_NAMES}). * * @since 1.5 */ CANONICALIZE_FIELD_NAMES(true), ; final boolean _defaultState; /** * Method that calculates bit set (flags) of all features that * are enabled by default. */ public static int collectDefaults() { int flags = 0; for (Feature f : values()) { if (f.enabledByDefault()) { flags |= f.getMask(); } } return flags; } private Feature(boolean defaultState) { _defaultState = defaultState; } public boolean enabledByDefault() { return _defaultState; } public boolean enabledIn(int flags) { return (flags & getMask()) != 0; } public int getMask() { return (1 << ordinal()); } }; /* /********************************************************** /* Minimal configuration state /********************************************************** */ /** * Bit flag composed of bits that indicate which * {@link org.codehaus.jackson.JsonParser.Feature}s * are enabled. */ protected int _features; /* /********************************************************** /* Minimal generic state /********************************************************** */ /** * Last token retrieved via {@link #nextToken}, if any. * Null before the first call to nextToken(), * as well as if token has been explicitly cleared * (by call to {@link #clearCurrentToken}) */ protected JsonToken _currToken; /** * Last cleared token, if any: that is, value that was in * effect when {@link #clearCurrentToken} was called. */ protected JsonToken _lastClearedToken; /* /********************************************************** /* Construction, configuration, initialization /********************************************************** */ protected JsonParser() { } protected JsonParser(int features) { _features = features; } /** * Accessor for {@link ObjectCodec} associated with this * parser, if any. Codec is used by {@link #readValueAs(Class)} * method (and its variants). * * @since 1.3 */ public abstract ObjectCodec getCodec(); /** * Setter that allows defining {@link ObjectCodec} associated with this * parser, if any. Codec is used by {@link #readValueAs(Class)} * method (and its variants). * * @since 1.3 */ public abstract void setCodec(ObjectCodec c); /** * Method to call to make this parser use specified schema. Method must * be called before trying to parse any content, right after parser instance * has been created. * Note that not all parsers support schemas; and those that do usually only * accept specific types of schemas: ones defined for data format parser can read. *

* If parser does not support specified schema, {@link UnsupportedOperationException} * is thrown. * * @param schema Schema to use * * @throws UnsupportedOperationException if parser does not support schema * * @since 1.8 */ public void setSchema(FormatSchema schema) { throw new UnsupportedOperationException("Parser of type "+getClass().getName()+" does not support schema of type '" +schema.getSchemaType()+"'"); } /** * Method that can be used to verify that given schema can be used with * this parser (using {@link #setSchema}). * * @param schema Schema to check * * @return True if this parser can use given schema; false if not * * @since 1.8 */ public boolean canUseSchema(FormatSchema schema) { return false; } /** * @since 1.6 */ @Override public Version version() { return Version.unknownVersion(); } /** * Method that can be used to get access to object that is used * to access input being parsed; this is usually either * {@link InputStream} or {@link Reader}, depending on what * parser was constructed with. * Note that returned value may be null in some cases; including * case where parser implementation does not want to exposed raw * source to caller. * In cases where input has been decorated, object returned here * is the decorated version; this allows some level of interaction * between users of parser and decorator object. *

* In general use of this accessor should be considered as * "last effort", i.e. only used if no other mechanism is applicable. * * @since 1.8 */ public Object getInputSource() { return null; } /* /********************************************************** /* Closeable implementation /********************************************************** */ /** * Closes the parser so that no further iteration or data access * can be made; will also close the underlying input source * if parser either owns the input source, or feature * {@link Feature#AUTO_CLOSE_SOURCE} is enabled. * Whether parser owns the input source depends on factory * method that was used to construct instance (so check * {@link org.codehaus.jackson.JsonFactory} for details, * but the general * idea is that if caller passes in closable resource (such * as {@link InputStream} or {@link Reader}) parser does NOT * own the source; but if it passes a reference (such as * {@link java.io.File} or {@link java.net.URL} and creates * stream or reader it does own them. */ @Override public abstract void close() throws IOException; /* /********************************************************** /* Buffer handling /********************************************************** */ /** * Method that can be called to push back any content that * has been read but not consumed by the parser. This is usually * done after reading all content of interest using parser. * Content is released by writing it to given stream if possible; * if underlying input is byte-based it can released, if not (char-based) * it can not. * * @return -1 if the underlying content source is not byte based * (that is, input can not be sent to {@link OutputStream}; * otherwise number of bytes released (0 if there was nothing to release) * * @throws IOException if write to stream threw exception * * @since 1.6 */ public int releaseBuffered(OutputStream out) throws IOException { return -1; } /** * Method that can be called to push back any content that * has been read but not consumed by the parser. * This is usually * done after reading all content of interest using parser. * Content is released by writing it to given writer if possible; * if underlying input is char-based it can released, if not (byte-based) * it can not. * * @return -1 if the underlying content source is not char-based * (that is, input can not be sent to {@link Writer}; * otherwise number of chars released (0 if there was nothing to release) * * @throws IOException if write using Writer threw exception * * @since 1.6 */ public int releaseBuffered(Writer w) throws IOException { return -1; } /* /*************************************************** /* Public API, configuration /*************************************************** */ /** * Method for enabling specified parser feature * (check {@link Feature} for list of features) * * @since 1.2 */ public JsonParser enable(Feature f) { _features |= f.getMask(); return this; } /** * Method for disabling specified feature * (check {@link Feature} for list of features) * * @since 1.2 */ public JsonParser disable(Feature f) { _features &= ~f.getMask(); return this; } /** * Method for enabling or disabling specified feature * (check {@link Feature} for list of features) * * @since 1.2 */ public JsonParser configure(Feature f, boolean state) { if (state) { enableFeature(f); } else { disableFeature(f); } return this; } /** * Method for checking whether specified {@link Feature} * is enabled. * * @since 1.2 */ public boolean isEnabled(Feature f) { return (_features & f.getMask()) != 0; } /** @deprecated Use {@link #configure} instead */ @SuppressWarnings("dep-ann") public void setFeature(Feature f, boolean state) { configure(f, state); } /** @deprecated Use {@link #enable(Feature)} instead */ @SuppressWarnings("dep-ann") public void enableFeature(Feature f) { enable(f); } /** @deprecated Use {@link #disable(Feature)} instead */ @SuppressWarnings("dep-ann") public void disableFeature(Feature f) { disable(f); } /** @deprecated Use {@link #isEnabled(Feature)} instead */ @SuppressWarnings("dep-ann") public final boolean isFeatureEnabled(Feature f) { return isEnabled(f); } /* /********************************************************** /* Public API, traversal /********************************************************** */ /** * Main iteration method, which will advance stream enough * to determine type of the next token, if any. If none * remaining (stream has no content other than possible * white space before ending), null will be returned. * * @return Next token from the stream, if any found, or null * to indicate end-of-input */ public abstract JsonToken nextToken() throws IOException, JsonParseException; /** * Iteration method that will advance stream enough * to determine type of the next token that is a value type * (including JSON Array and Object start/end markers). * Or put another way, nextToken() will be called once, * and if {@link JsonToken#FIELD_NAME} is returned, another * time to get the value for the field. * Method is most useful for iterating over value entries * of JSON objects; field name will still be available * by calling {@link #getCurrentName} when parser points to * the value. * * @return Next non-field-name token from the stream, if any found, * or null to indicate end-of-input (or, for non-blocking * parsers, {@link JsonToken#NOT_AVAILABLE} if no tokens were * available yet) */ public JsonToken nextValue() throws IOException, JsonParseException { /* Implementation should be as trivial as follows; only * needs to change if we are to skip other tokens (for * example, if comments were exposed as tokens) */ JsonToken t = nextToken(); if (t == JsonToken.FIELD_NAME) { t = nextToken(); } return t; } /** * Method that fetches next token (as if calling {@link #nextToken}) and * verifies whether it is {@link JsonToken#FIELD_NAME} with specified name * and returns result of that comparison. * It is functionally equivalent to: *

     *  return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName());
     *
* but may be faster for parser to verify, and can therefore be used if caller * expects to get such a property name from input next. * * @param str Property name to compare next token to (if next token is JsonToken.FIELD_NAME) * * @since 1.9 */ public boolean nextFieldName(SerializableString str) throws IOException, JsonParseException { return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName()); } /** * Method that fetches next token (as if calling {@link #nextToken}) and * if it is {@link JsonToken#VALUE_STRING} returns contained String value; * otherwise returns null. * It is functionally equivalent to: *
     *  return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
     *
* but may be faster for parser to process, and can therefore be used if caller * expects to get a String value next from input. * * @since 1.9 */ public String nextTextValue() throws IOException, JsonParseException { return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null; } /** * Method that fetches next token (as if calling {@link #nextToken}) and * if it is {@link JsonToken#VALUE_NUMBER_INT} returns 32-bit int value; * otherwise returns specified default value * It is functionally equivalent to: *
     *  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
     *
* but may be faster for parser to process, and can therefore be used if caller * expects to get a String value next from input. * * @since 1.9 */ public int nextIntValue(int defaultValue) throws IOException, JsonParseException { return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue; } /** * Method that fetches next token (as if calling {@link #nextToken}) and * if it is {@link JsonToken#VALUE_NUMBER_INT} returns 64-bit long value; * otherwise returns specified default value * It is functionally equivalent to: *
     *  return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
     *
* but may be faster for parser to process, and can therefore be used if caller * expects to get a String value next from input. * * @since 1.9 */ public long nextLongValue(long defaultValue) throws IOException, JsonParseException { return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue; } /** * Method that fetches next token (as if calling {@link #nextToken}) and * if it is {@link JsonToken#VALUE_TRUE} or {@link JsonToken#VALUE_FALSE} * returns matching Boolean value; otherwise return null. * It is functionally equivalent to: *
     *  JsonToken t = nextToken();
     *  if (t == JsonToken.VALUE_TRUE) return Boolean.TRUE;
     *  if (t == JsonToken.VALUE_FALSE) return Boolean.FALSE;
     *  return null;
     *
* but may be faster for parser to process, and can therefore be used if caller * expects to get a String value next from input. * * @since 1.9 */ public Boolean nextBooleanValue() throws IOException, JsonParseException { switch (nextToken()) { case VALUE_TRUE: return Boolean.TRUE; case VALUE_FALSE: return Boolean.FALSE; } return null; } /** * Method that will skip all child tokens of an array or * object token that the parser currently points to, * iff stream points to * {@link JsonToken#START_OBJECT} or {@link JsonToken#START_ARRAY}. * If not, it will do nothing. * After skipping, stream will point to matching * {@link JsonToken#END_OBJECT} or {@link JsonToken#END_ARRAY} * (possibly skipping nested pairs of START/END OBJECT/ARRAY tokens * as well as value tokens). * The idea is that after calling this method, application * will call {@link #nextToken} to point to the next * available token, if any. */ public abstract JsonParser skipChildren() throws IOException, JsonParseException; /** * Method that can be called to determine whether this parser * is closed or not. If it is closed, no new tokens can be * retrieved by calling {@link #nextToken} (and the underlying * stream may be closed). Closing may be due to an explicit * call to {@link #close} or because parser has encountered * end of input. */ public abstract boolean isClosed(); /* /********************************************************** /* Public API, token accessors /********************************************************** */ /** * Accessor to find which token parser currently points to, if any; * null will be returned if none. * If return value is non-null, data associated with the token * is available via other accessor methods. * * @return Type of the token this parser currently points to, * if any: null before any tokens have been read, and * after end-of-input has been encountered, as well as * if the current token has been explicitly cleared. */ public JsonToken getCurrentToken() { return _currToken; } /** * Method for checking whether parser currently points to * a token (and data for that token is available). * Equivalent to check for parser.getCurrentToken() != null. * * @return True if the parser just returned a valid * token via {@link #nextToken}; false otherwise (parser * was just constructed, encountered end-of-input * and returned null from {@link #nextToken}, or the token * has been consumed) */ public boolean hasCurrentToken() { return _currToken != null; } /** * Method called to "consume" the current token by effectively * removing it so that {@link #hasCurrentToken} returns false, and * {@link #getCurrentToken} null). * Cleared token value can still be accessed by calling * {@link #getLastClearedToken} (if absolutely needed), but * usually isn't. *

* Method was added to be used by the optional data binder, since * it has to be able to consume last token used for binding (so that * it will not be used again). */ public void clearCurrentToken() { if (_currToken != null) { _lastClearedToken = _currToken; _currToken = null; } } /** * Method that can be called to get the name associated with * the current token: for {@link JsonToken#FIELD_NAME}s it will * be the same as what {@link #getText} returns; * for field values it will be preceding field name; * and for others (array values, root-level values) null. */ public abstract String getCurrentName() throws IOException, JsonParseException; /** * Method that can be used to access current parsing context reader * is in. There are 3 different types: root, array and object contexts, * with slightly different available information. Contexts are * hierarchically nested, and can be used for example for figuring * out part of the input document that correspond to specific * array or object (for highlighting purposes, or error reporting). * Contexts can also be used for simple xpath-like matching of * input, if so desired. */ public abstract JsonStreamContext getParsingContext(); /** * Method that return the starting location of the current * token; that is, position of the first character from input * that starts the current token. */ public abstract JsonLocation getTokenLocation(); /** * Method that returns location of the last processed character; * usually for error reporting purposes. */ public abstract JsonLocation getCurrentLocation(); /** * Method that can be called to get the last token that was * cleared using {@link #clearCurrentToken}. This is not necessarily * the latest token read. * Will return null if no tokens have been cleared, * or if parser has been closed. */ public JsonToken getLastClearedToken() { return _lastClearedToken; } /** * Specialized accessor that can be used to verify that the current * token indicates start array (usually meaning that current token * is {@link JsonToken#START_ARRAY}) when start array is expected. * For some specialized parsers this can return true for other cases * as well; this is usually done to emulate arrays. *

* Default implementation is equivalent to: *

     *   getCurrentToken() == JsonToken.START_ARRAY
     *
* but may be overridden by custom parser implementations. * * @return True if the current token can be considered as a * start-array marker (such {@link JsonToken#START_ARRAY}); * false if not. * * @since 1.7 */ public boolean isExpectedStartArrayToken() { return getCurrentToken() == JsonToken.START_ARRAY; } /* /********************************************************** /* Public API, access to token information, text /********************************************************** */ /** * Method for accessing textual representation of the current token; * if no current token (before first call to {@link #nextToken}, or * after encountering end-of-input), returns null. * Method can be called for any token type. */ public abstract String getText() throws IOException, JsonParseException; /** * Method similar to {@link #getText}, but that will return * underlying (unmodifiable) character array that contains * textual value, instead of constructing a String object * to contain this information. * Note, however, that: *
    *
  • Textual contents are not guaranteed to start at * index 0 (rather, call {@link #getTextOffset}) to * know the actual offset *
  • *
  • Length of textual contents may be less than the * length of returned buffer: call {@link #getTextLength} * for actual length of returned content. *
  • *
*

* Note that caller MUST NOT modify the returned * character array in any way -- doing so may corrupt * current parser state and render parser instance useless. *

* The only reason to call this method (over {@link #getText}) * is to avoid construction of a String object (which * will make a copy of contents). */ public abstract char[] getTextCharacters() throws IOException, JsonParseException; /** * Accessor used with {@link #getTextCharacters}, to know length * of String stored in returned buffer. * * @return Number of characters within buffer returned * by {@link #getTextCharacters} that are part of * textual content of the current token. */ public abstract int getTextLength() throws IOException, JsonParseException; /** * Accessor used with {@link #getTextCharacters}, to know offset * of the first text content character within buffer. * * @return Offset of the first character within buffer returned * by {@link #getTextCharacters} that is part of * textual content of the current token. */ public abstract int getTextOffset() throws IOException, JsonParseException; /** * Method that can be used to determine whether calling of * {@link #getTextCharacters} would be the most efficient * way to access textual content for the event parser currently * points to. *

* Default implementation simply returns false since only actual * implementation class has knowledge of its internal buffering * state. * Implementations are strongly encouraged to properly override * this method, to allow efficient copying of content by other * code. * * @return True if parser currently has character array that can * be efficiently returned via {@link #getTextCharacters}; false * means that it may or may not exist * * @since 1.6 */ public boolean hasTextCharacters() { return false; } /* /********************************************************** /* Public API, access to token information, numeric /********************************************************** */ /** * Generic number value accessor method that will work for * all kinds of numeric values. It will return the optimal * (simplest/smallest possible) wrapper object that can * express the numeric value just parsed. */ public abstract Number getNumberValue() throws IOException, JsonParseException; /** * If current token is of type * {@link JsonToken#VALUE_NUMBER_INT} or * {@link JsonToken#VALUE_NUMBER_FLOAT}, returns * one of {@link NumberType} constants; otherwise returns null. */ public abstract NumberType getNumberType() throws IOException, JsonParseException; /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_INT} and * it can be expressed as a value of Java byte primitive type. * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; * if so, it is equivalent to calling {@link #getDoubleValue} * and then casting; except for possible overflow/underflow * exception. *

* Note: if the resulting integer value falls outside range of * Java byte, a {@link JsonParseException} * will be thrown to indicate numeric overflow/underflow. */ public byte getByteValue() throws IOException, JsonParseException { int value = getIntValue(); // So far so good: but does it fit? if (value < MIN_BYTE_I || value > MAX_BYTE_I) { throw _constructError("Numeric value ("+getText()+") out of range of Java byte"); } return (byte) value; } /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_INT} and * it can be expressed as a value of Java short primitive type. * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; * if so, it is equivalent to calling {@link #getDoubleValue} * and then casting; except for possible overflow/underflow * exception. *

* Note: if the resulting integer value falls outside range of * Java short, a {@link JsonParseException} * will be thrown to indicate numeric overflow/underflow. */ public short getShortValue() throws IOException, JsonParseException { int value = getIntValue(); if (value < MIN_SHORT_I || value > MAX_SHORT_I) { throw _constructError("Numeric value ("+getText()+") out of range of Java short"); } return (short) value; } /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_INT} and * it can be expressed as a value of Java int primitive type. * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; * if so, it is equivalent to calling {@link #getDoubleValue} * and then casting; except for possible overflow/underflow * exception. *

* Note: if the resulting integer value falls outside range of * Java int, a {@link JsonParseException} * may be thrown to indicate numeric overflow/underflow. */ public abstract int getIntValue() throws IOException, JsonParseException; /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_INT} and * it can be expressed as a Java long primitive type. * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; * if so, it is equivalent to calling {@link #getDoubleValue} * and then casting to int; except for possible overflow/underflow * exception. *

* Note: if the token is an integer, but its value falls * outside of range of Java long, a {@link JsonParseException} * may be thrown to indicate numeric overflow/underflow. */ public abstract long getLongValue() throws IOException, JsonParseException; /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_INT} and * it can not be used as a Java long primitive type due to its * magnitude. * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT}; * if so, it is equivalent to calling {@link #getDecimalValue} * and then constructing a {@link BigInteger} from that value. */ public abstract BigInteger getBigIntegerValue() throws IOException, JsonParseException; /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} and * it can be expressed as a Java float primitive type. * It can also be called for {@link JsonToken#VALUE_NUMBER_INT}; * if so, it is equivalent to calling {@link #getLongValue} * and then casting; except for possible overflow/underflow * exception. *

* Note: if the value falls * outside of range of Java float, a {@link JsonParseException} * will be thrown to indicate numeric overflow/underflow. */ public abstract float getFloatValue() throws IOException, JsonParseException; /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} and * it can be expressed as a Java double primitive type. * It can also be called for {@link JsonToken#VALUE_NUMBER_INT}; * if so, it is equivalent to calling {@link #getLongValue} * and then casting; except for possible overflow/underflow * exception. *

* Note: if the value falls * outside of range of Java double, a {@link JsonParseException} * will be thrown to indicate numeric overflow/underflow. */ public abstract double getDoubleValue() throws IOException, JsonParseException; /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} or * {@link JsonToken#VALUE_NUMBER_INT}. No under/overflow exceptions * are ever thrown. */ public abstract BigDecimal getDecimalValue() throws IOException, JsonParseException; /* /********************************************************** /* Public API, access to token information, other /********************************************************** */ /** * Convenience accessor that can be called when the current * token is {@link JsonToken#VALUE_TRUE} or * {@link JsonToken#VALUE_FALSE}. *

* Note: if the token is not of above-mentioned boolean types, an integer, but its value falls * outside of range of Java long, a {@link JsonParseException} * may be thrown to indicate numeric overflow/underflow. * * @since 1.3 */ public boolean getBooleanValue() throws IOException, JsonParseException { if (_currToken == JsonToken.VALUE_TRUE) return true; if (_currToken == JsonToken.VALUE_FALSE) return false; throw new JsonParseException("Current token ("+_currToken+") not of boolean type", getCurrentLocation()); } /** * Accessor that can be called if (and only if) the current token * is {@link JsonToken#VALUE_EMBEDDED_OBJECT}. For other token types, * null is returned. *

* Note: only some specialized parser implementations support * embedding of objects (usually ones that are facades on top * of non-streaming sources, such as object trees). * * @since 1.3 */ public Object getEmbeddedObject() throws IOException, JsonParseException { // By default we will always return null return null; } /* /********************************************************** /* Public API, access to token information, binary /********************************************************** */ /** * Method that can be used to read (and consume -- results * may not be accessible using other methods after the call) * base64-encoded binary data * included in the current textual JSON value. * It works similar to getting String value via {@link #getText} * and decoding result (except for decoding part), * but should be significantly more performant. *

* Note that non-decoded textual contents of the current token * are not guaranteed to be accessible after this method * is called. Current implementation, for example, clears up * textual content during decoding. * Decoded binary content, however, will be retained until * parser is advanced to the next event. * * @param b64variant Expected variant of base64 encoded * content (see {@link Base64Variants} for definitions * of "standard" variants). * * @return Decoded binary data */ public abstract byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException; /** * Convenience alternative to {@link #getBinaryValue(Base64Variant)} * that defaults to using * {@link Base64Variants#getDefaultVariant} as the default encoding. */ public byte[] getBinaryValue() throws IOException, JsonParseException { return getBinaryValue(Base64Variants.getDefaultVariant()); } /* /********************************************************** /* Public API, access to token information, coercion/conversion /********************************************************** */ /** * Method that will try to convert value of current token to a * int. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured type * markers like start/end Object/Array) * default value of 0 will be returned; no exceptions are thrown. * * @since 1.6 */ public int getValueAsInt() throws IOException, JsonParseException { return getValueAsInt(0); } /** * Method that will try to convert value of current token to a * int. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured type * markers like start/end Object/Array) * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.6 */ public int getValueAsInt(int defaultValue) throws IOException, JsonParseException { return defaultValue; } /** * Method that will try to convert value of current token to a * long. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured type * markers like start/end Object/Array) * default value of 0 will be returned; no exceptions are thrown. * * @since 1.6 */ public long getValueAsLong() throws IOException, JsonParseException { return getValueAsInt(0); } /** * Method that will try to convert value of current token to a * long. * Numbers are coerced using default Java rules; booleans convert to 0 (false) * and 1 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured type * markers like start/end Object/Array) * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.6 */ public long getValueAsLong(long defaultValue) throws IOException, JsonParseException { return defaultValue; } /** * Method that will try to convert value of current token to a Java * double. * Numbers are coerced using default Java rules; booleans convert to 0.0 (false) * and 1.0 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * default value of 0.0 will be returned; no exceptions are thrown. * * @since 1.6 */ public double getValueAsDouble() throws IOException, JsonParseException { return getValueAsDouble(0.0); } /** * Method that will try to convert value of current token to a * Java double. * Numbers are coerced using default Java rules; booleans convert to 0.0 (false) * and 1.0 (true), and Strings are parsed using default Java language integer * parsing rules. *

* If representation can not be converted to an int (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.6 */ public double getValueAsDouble(double defaultValue) throws IOException, JsonParseException { return defaultValue; } /** * Method that will try to convert value of current token to a * boolean. * JSON booleans map naturally; integer numbers other than 0 map to true, and * 0 maps to false * and Strings 'true' and 'false' map to corresponding values. *

* If representation can not be converted to a boolean value (including structured types * like Objects and Arrays), * default value of false will be returned; no exceptions are thrown. * * @since 1.7 */ public boolean getValueAsBoolean() throws IOException, JsonParseException { return getValueAsBoolean(false); } /** * Method that will try to convert value of current token to a * boolean. * JSON booleans map naturally; integer numbers other than 0 map to true, and * 0 maps to false * and Strings 'true' and 'false' map to corresponding values. *

* If representation can not be converted to a boolean value (including structured types * like Objects and Arrays), * specified defaultValue will be returned; no exceptions are thrown. * * @since 1.7 */ public boolean getValueAsBoolean(boolean defaultValue) throws IOException, JsonParseException { return defaultValue; } /* /********************************************************** /* Public API, optional data binding functionality /********************************************************** */ /** * Method to deserialize JSON content into a non-container * type (it can be an array type, however): typically a bean, array * or a wrapper type (like {@link java.lang.Boolean}). * Note: method can only be called if the parser has * an object codec assigned; this is true for parsers constructed * by {@link org.codehaus.jackson.map.MappingJsonFactory} but * not for {@link JsonFactory} (unless its setCodec * method has been explicitly called). *

* This method may advance the event stream, for structured types * the current token will be the closing end marker (END_ARRAY, * END_OBJECT) of the bound structure. For non-structured Json types * (and for {@link JsonToken#VALUE_EMBEDDED_OBJECT}) * stream is not advanced. *

* Note: this method should NOT be used if the result type is a * container ({@link java.util.Collection} or {@link java.util.Map}. * The reason is that due to type erasure, key and value types * can not be introspected when using this method. */ public T readValueAs(Class valueType) throws IOException, JsonProcessingException { ObjectCodec codec = getCodec(); if (codec == null) { throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into Java objects"); } return codec.readValue(this, valueType); } /** * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using so-called * "super type token" * and specifically needs to be used if the root type is a * parameterized (generic) container type. * Note: method can only be called if the parser has * an object codec assigned; this is true for parsers constructed * by {@link org.codehaus.jackson.map.MappingJsonFactory} but * not for {@link JsonFactory} (unless its setCodec * method has been explicitly called). *

* This method may advance the event stream, for structured types * the current token will be the closing end marker (END_ARRAY, * END_OBJECT) of the bound structure. For non-structured Json types * (and for {@link JsonToken#VALUE_EMBEDDED_OBJECT}) * stream is not advanced. */ @SuppressWarnings("unchecked") public T readValueAs(TypeReference valueTypeRef) throws IOException, JsonProcessingException { ObjectCodec codec = getCodec(); if (codec == null) { throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into Java objects"); } /* Ugh. Stupid Java type erasure... can't just chain call,s * must cast here also. */ return (T) codec.readValue(this, valueTypeRef); } /** * Method for reading sequence of Objects from parser stream, * all with same specified value type. * * @since 1.9 */ public Iterator readValuesAs(Class valueType) throws IOException, JsonProcessingException { ObjectCodec codec = getCodec(); if (codec == null) { throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into Java objects"); } return codec.readValues(this, valueType); } /** * Method for reading sequence of Objects from parser stream, * all with same specified value type. * * @since 1.9 */ public Iterator readValuesAs(TypeReference valueTypeRef) throws IOException, JsonProcessingException { ObjectCodec codec = getCodec(); if (codec == null) { throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into Java objects"); } return codec.readValues(this, valueTypeRef); } /** * Method to deserialize JSON content into equivalent "tree model", * represented by root {@link JsonNode} of resulting model. * For JSON Arrays it will an array node (with child nodes), * for objects object node (with child nodes), and for other types * matching leaf node type */ public JsonNode readValueAsTree() throws IOException, JsonProcessingException { ObjectCodec codec = getCodec(); if (codec == null) { throw new IllegalStateException("No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree"); } return codec.readTree(this); } /* /********************************************************** /* Internal methods /********************************************************** */ /** * Helper method for constructing {@link JsonParseException}s * based on current state of the parser */ protected JsonParseException _constructError(String msg) { return new JsonParseException(msg, getCurrentLocation()); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/0000755000175000017500000000000011672662540022755 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/sym/CharsToNameCanonicalizer.java0000644000175000017500000004627611655120726030501 0ustar jamespagejamespagepackage org.codehaus.jackson.sym; import java.util.Arrays; import org.codehaus.jackson.util.InternCache; /** * This class is a kind of specialized type-safe Map, from char array to * String value. Specialization means that in addition to type-safety * and specific access patterns (key char array, Value optionally interned * String; values added on access if necessary), and that instances are * meant to be used concurrently, but by using well-defined mechanisms * to obtain such concurrently usable instances. Main use for the class * is to store symbol table information for things like compilers and * parsers; especially when number of symbols (keywords) is limited. *

* For optimal performance, usage pattern should be one where matches * should be very common (esp. after "warm-up"), and as with most hash-based * maps/sets, that hash codes are uniformly distributed. Also, collisions * are slightly more expensive than with HashMap or HashSet, since hash codes * are not used in resolving collisions; that is, equals() comparison is * done with all symbols in same bucket index.
* Finally, rehashing is also more expensive, as hash codes are not * stored; rehashing requires all entries' hash codes to be recalculated. * Reason for not storing hash codes is reduced memory usage, hoping * for better memory locality. *

* Usual usage pattern is to create a single "master" instance, and either * use that instance in sequential fashion, or to create derived "child" * instances, which after use, are asked to return possible symbol additions * to master instance. In either case benefit is that symbol table gets * initialized so that further uses are more efficient, as eventually all * symbols needed will already be in symbol table. At that point no more * Symbol String allocations are needed, nor changes to symbol table itself. *

* Note that while individual SymbolTable instances are NOT thread-safe * (much like generic collection classes), concurrently used "child" * instances can be freely used without synchronization. However, using * master table concurrently with child instances can only be done if * access to master instance is read-only (ie. no modifications done). */ public final class CharsToNameCanonicalizer { /** * Default initial table size. Shouldn't be miniscule (as there's * cost to both array realloc and rehashing), but let's keep * it reasonably small nonetheless. For systems that properly * reuse factories it doesn't matter either way; but when * recreating factories often, initial overhead may dominate. */ protected static final int DEFAULT_TABLE_SIZE = 64; /** * Let's not expand symbol tables past some maximum size; * this should protected against OOMEs caused by large documents * with uniquer (~= random) names. * * @since 1.5 */ protected static final int MAX_TABLE_SIZE = 0x10000; // 64k entries == 256k mem /** * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k; * this corresponds to 64k main hash index. This should allow for enough distinct * names for almost any case. */ final static int MAX_ENTRIES_FOR_REUSE = 12000; final static CharsToNameCanonicalizer sBootstrapSymbolTable; static { sBootstrapSymbolTable = new CharsToNameCanonicalizer(); } /* /**************************************** /* Configuration: /**************************************** */ /** * Sharing of learnt symbols is done by optional linking of symbol * table instances with their parents. When parent linkage is * defined, and child instance is released (call to release), * parent's shared tables may be updated from the child instance. */ protected CharsToNameCanonicalizer _parent; /** * Whether canonical symbol Strings are to be intern()ed before added * to the table or not */ final protected boolean _intern; /** * Whether any canonicalization should be attempted (whether using * intern or not) */ final protected boolean _canonicalize; /* /**************************************** /* Actual symbol table data: /**************************************** */ /** * Primary matching symbols; it's expected most match occur from * here. */ protected String[] _symbols; /** * Overflow buckets; if primary doesn't match, lookup is done * from here. *

* Note: Number of buckets is half of number of symbol entries, on * assumption there's less need for buckets. */ protected Bucket[] _buckets; /** * Current size (number of entries); needed to know if and when * rehash. */ protected int _size; /** * Limit that indicates maximum size this instance can hold before * it needs to be expanded and rehashed. Calculated using fill * factor passed in to constructor. */ protected int _sizeThreshold; /** * Mask used to get index from hash values; equal to * _buckets.length - 1, when _buckets.length is * a power of two. */ protected int _indexMask; /* /**************************************** /* State regarding shared arrays /**************************************** */ /** * Flag that indicates if any changes have been made to the data; * used to both determine if bucket array needs to be copied when * (first) change is made, and potentially if updated bucket list * is to be resync'ed back to master instance. */ protected boolean _dirty; /* /**************************************** /* Life-cycle /**************************************** */ /** * Method called to create root canonicalizer for a {@link org.codehaus.jackson.JsonFactory} * instance. Root instance is never used directly; its main use is for * storing and sharing underlying symbol arrays as needed. */ public static CharsToNameCanonicalizer createRoot() { return sBootstrapSymbolTable.makeOrphan(); } /** * Main method for constructing a master symbol table instance. * * @param initialSize Minimum initial size for bucket array; internally * will always use a power of two equal to or bigger than this value. */ private CharsToNameCanonicalizer() { // these settings don't really matter for the bootstrap instance _canonicalize = true; _intern = true; // And we'll also set flags so no copying of buckets is needed: _dirty = true; initTables(DEFAULT_TABLE_SIZE); } private void initTables(int initialSize) { _symbols = new String[initialSize]; _buckets = new Bucket[initialSize >> 1]; // Mask is easy to calc for powers of two. _indexMask = initialSize - 1; _size = 0; // Hard-coded fill factor is 75% _sizeThreshold = (initialSize - (initialSize >> 2)); } /** * Internal constructor used when creating child instances. */ private CharsToNameCanonicalizer(CharsToNameCanonicalizer parent, boolean canonicalize, boolean intern, String[] symbols, Bucket[] buckets, int size) { _parent = parent; _canonicalize = canonicalize; _intern = intern; _symbols = symbols; _buckets = buckets; _size = size; // Hard-coded fill factor, 75% int arrayLen = (symbols.length); _sizeThreshold = arrayLen - (arrayLen >> 2); _indexMask = (arrayLen - 1); // Need to make copies of arrays, if/when adding new entries _dirty = false; } /** * "Factory" method; will create a new child instance of this symbol * table. It will be a copy-on-write instance, ie. it will only use * read-only copy of parent's data, but when changes are needed, a * copy will be created. *

* Note: while this method is synchronized, it is generally not * safe to both use makeChild/mergeChild, AND to use instance * actively. Instead, a separate 'root' instance should be used * on which only makeChild/mergeChild are called, but instance itself * is not used as a symbol table. */ public synchronized CharsToNameCanonicalizer makeChild(boolean canonicalize, boolean intern) { return new CharsToNameCanonicalizer(this, canonicalize, intern, _symbols, _buckets, _size); } private CharsToNameCanonicalizer makeOrphan() { return new CharsToNameCanonicalizer(null, true, true, _symbols, _buckets, _size); } /** * Method that allows contents of child table to potentially be * "merged in" with contents of this symbol table. *

* Note that caller has to make sure symbol table passed in is * really a child or sibling of this symbol table. */ private synchronized void mergeChild(CharsToNameCanonicalizer child) { /* One caveat: let's try to avoid problems with * degenerate cases of documents with generated "random" * names: for these, symbol tables would bloat indefinitely. * One way to do this is to just purge tables if they grow * too large, and that's what we'll do here. */ if (child.size() > MAX_ENTRIES_FOR_REUSE) { /* Should there be a way to get notified about this * event, to log it or such? (as it's somewhat abnormal * thing to happen) */ // At any rate, need to clean up the tables, then: initTables(DEFAULT_TABLE_SIZE); } else { /* Otherwise, we'll merge changed stuff in, if there are * more entries (which may not be the case if one of siblings * has added symbols first or such) */ if (child.size() <= size()) { // nothing to add return; } // Okie dokie, let's get the data in! _symbols = child._symbols; _buckets = child._buckets; _size = child._size; _sizeThreshold = child._sizeThreshold; _indexMask = child._indexMask; } /* Dirty flag... well, let's just clear it, to force copying just * in case. Shouldn't really matter, for master tables. * (which this is, given something is merged to it etc) */ _dirty = false; } public void release() { // If nothing has been added, nothing to do if (!maybeDirty()) { return; } if (_parent != null) { _parent.mergeChild(this); /* Let's also mark this instance as dirty, so that just in * case release was too early, there's no corruption * of possibly shared data. */ _dirty = false; } } /* /**************************************** /* Public API, generic accessors: /**************************************** */ public int size() { return _size; } public boolean maybeDirty() { return _dirty; } /* /**************************************** /* Public API, accessing symbols: /**************************************** */ public String findSymbol(char[] buffer, int start, int len, int hash) { if (len < 1) { // empty Strings are simplest to handle up front return ""; } if (!_canonicalize) { // [JACKSON-259] return new String(buffer, start, len); } hash &= _indexMask; String sym = _symbols[hash]; // Optimal case; checking existing primary symbol for hash index: if (sym != null) { // Let's inline primary String equality checking: if (sym.length() == len) { int i = 0; do { if (sym.charAt(i) != buffer[start+i]) { break; } } while (++i < len); // Optimal case; primary match found if (i == len) { return sym; } } // How about collision bucket? Bucket b = _buckets[hash >> 1]; if (b != null) { sym = b.find(buffer, start, len); if (sym != null) { return sym; } } } if (!_dirty) { //need to do copy-on-write? copyArrays(); _dirty = true; } else if (_size >= _sizeThreshold) { // Need to expand? rehash(); /* Need to recalc hash; rare occurence (index mask has been * recalculated as part of rehash) */ hash = calcHash(buffer, start, len) & _indexMask; } ++_size; String newSymbol = new String(buffer, start, len); if (_intern) { newSymbol = InternCache.instance.intern(newSymbol); } // Ok; do we need to add primary entry, or a bucket? if (_symbols[hash] == null) { _symbols[hash] = newSymbol; } else { int bix = hash >> 1; _buckets[bix] = new Bucket(newSymbol, _buckets[bix]); } return newSymbol; } /** * Implementation of a hashing method for variable length * Strings. Most of the time intention is that this calculation * is done by caller during parsing, not here; however, sometimes * it needs to be done for parsed "String" too. * * @param len Length of String; has to be at least 1 (caller guarantees * this pre-condition) */ public static int calcHash(char[] buffer, int start, int len) { int hash = (int) buffer[0]; for (int i = 1; i < len; ++i) { hash = (hash * 31) + (int) buffer[i]; } return hash; } public static int calcHash(String key) { int hash = (int) key.charAt(0); for (int i = 1, len = key.length(); i < len; ++i) { hash = (hash * 31) + (int) key.charAt(i); } return hash; } /* /**************************************** /* Internal methods /**************************************** */ /** * Method called when copy-on-write is needed; generally when first * change is made to a derived symbol table. */ private void copyArrays() { String[] oldSyms = _symbols; int size = oldSyms.length; _symbols = new String[size]; System.arraycopy(oldSyms, 0, _symbols, 0, size); Bucket[] oldBuckets = _buckets; size = oldBuckets.length; _buckets = new Bucket[size]; System.arraycopy(oldBuckets, 0, _buckets, 0, size); } /** * Method called when size (number of entries) of symbol table grows * so big that load factor is exceeded. Since size has to remain * power of two, arrays will then always be doubled. Main work * is really redistributing old entries into new String/Bucket * entries. */ private void rehash() { int size = _symbols.length; int newSize = size + size; /* 12-Mar-2010, tatu: Let's actually limit maximum size we are * prepared to use, to guard against OOME in case of unbounded * name sets (unique [non-repeating] names) */ if (newSize > MAX_TABLE_SIZE) { /* If this happens, there's no point in either growing or * shrinking hash areas. Rather, it's better to just clean * them up for reuse. */ _size = 0; Arrays.fill(_symbols, null); Arrays.fill(_buckets, null); _dirty = true; return; } String[] oldSyms = _symbols; Bucket[] oldBuckets = _buckets; _symbols = new String[newSize]; _buckets = new Bucket[newSize >> 1]; // Let's update index mask, threshold, now (needed for rehashing) _indexMask = newSize - 1; _sizeThreshold += _sizeThreshold; int count = 0; // let's do sanity check /* Need to do two loops, unfortunately, since spill-over area is * only half the size: */ for (int i = 0; i < size; ++i) { String symbol = oldSyms[i]; if (symbol != null) { ++count; int index = calcHash(symbol) & _indexMask; if (_symbols[index] == null) { _symbols[index] = symbol; } else { int bix = index >> 1; _buckets[bix] = new Bucket(symbol, _buckets[bix]); } } } size >>= 1; for (int i = 0; i < size; ++i) { Bucket b = oldBuckets[i]; while (b != null) { ++count; String symbol = b.getSymbol(); int index = calcHash(symbol) & _indexMask; if (_symbols[index] == null) { _symbols[index] = symbol; } else { int bix = index >> 1; _buckets[bix] = new Bucket(symbol, _buckets[bix]); } b = b.getNext(); } } if (count != _size) { throw new Error("Internal error on SymbolTable.rehash(): had "+_size+" entries; now have "+count+"."); } } /* /**************************************** /* Bucket class /**************************************** */ /** * This class is a symbol table entry. Each entry acts as a node * in a linked list. */ static final class Bucket { private final String _symbol; private final Bucket mNext; public Bucket(String symbol, Bucket next) { _symbol = symbol; mNext = next; } public String getSymbol() { return _symbol; } public Bucket getNext() { return mNext; } public String find(char[] buf, int start, int len) { String sym = _symbol; Bucket b = mNext; while (true) { // Inlined equality comparison: if (sym.length() == len) { int i = 0; do { if (sym.charAt(i) != buf[start+i]) { break; } } while (++i < len); if (i == len) { return sym; } } if (b == null) { break; } sym = b.getSymbol(); b = b.getNext(); } return null; } /* 26-Nov-2008, tatu: not used currently; if not used in near future, * let's just delete it. */ /* public String find(String str) { String sym = _symbol; Bucket b = mNext; while (true) { if (sym.equals(str)) { return sym; } if (b == null) { break; } sym = b.getSymbol(); b = b.getNext(); } return null; } */ } } jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/Name.java0000644000175000017500000000241511655120726024476 0ustar jamespagejamespagepackage org.codehaus.jackson.sym; /** * Base class for tokenized names (key strings in objects) that have * been tokenized from byte-based input sources (like * {@link java.io.InputStream}. * * @author Tatu Saloranta */ public abstract class Name { protected final String _name; protected final int _hashCode; protected Name(String name, int hashCode) { _name = name; _hashCode = hashCode; } public String getName() { return _name; } /* /********************************************************** /* Methods for package/core parser /********************************************************** */ public abstract boolean equals(int quad1); public abstract boolean equals(int quad1, int quad2); public abstract boolean equals(int[] quads, int qlen); /* /********************************************************** /* Overridden standard methods /********************************************************** */ @Override public String toString() { return _name; } @Override public final int hashCode() { return _hashCode; } @Override public boolean equals(Object o) { // Canonical instances, can usually just do identity comparison return (o == this); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/NameN.java0000644000175000017500000000345411655120726024620 0ustar jamespagejamespagepackage org.codehaus.jackson.sym; /** * Generic implementation of PName used for "long" names, where long * means that its byte (UTF-8) representation is 13 bytes or more. */ public final class NameN extends Name { final int[] mQuads; final int mQuadLen; NameN(String name, int hash, int[] quads, int quadLen) { super(name, hash); /* We have specialized implementations for shorter * names, so let's not allow runt instances here */ if (quadLen < 3) { throw new IllegalArgumentException("Qlen must >= 3"); } mQuads = quads; mQuadLen = quadLen; } // Implies quad length == 1, never matches @Override public boolean equals(int quad) { return false; } // Implies quad length == 2, never matches @Override public boolean equals(int quad1, int quad2) { return false; } @Override public boolean equals(int[] quads, int qlen) { if (qlen != mQuadLen) { return false; } /* 26-Nov-2008, tatus: Strange, but it does look like * unrolling here is counter-productive, reducing * speed. Perhaps it prevents inlining by HotSpot or * something... */ // Will always have >= 3 quads, can unroll /* if (quads[0] == mQuads[0] && quads[1] == mQuads[1] && quads[2] == mQuads[2]) { for (int i = 3; i < qlen; ++i) { if (quads[i] != mQuads[i]) { return false; } } return true; } */ // or simpler way without unrolling: for (int i = 0; i < qlen; ++i) { if (quads[i] != mQuads[i]) { return false; } } return true; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/Name2.java0000644000175000017500000000174711655120726024567 0ustar jamespagejamespagepackage org.codehaus.jackson.sym; /** * Specialized implementation of PName: can be used for short Strings * that consists of 5 to 8 bytes. Usually this means relatively short * ascii-only names. *

* The reason for such specialized classes is mostly space efficiency; * and to a lesser degree performance. Both are achieved for short * Strings by avoiding another level of indirection (via quad arrays) */ public final class Name2 extends Name { final int mQuad1; final int mQuad2; Name2(String name, int hash, int quad1, int quad2) { super(name, hash); mQuad1 = quad1; mQuad2 = quad2; } @Override public boolean equals(int quad) { return false; } @Override public boolean equals(int quad1, int quad2) { return (quad1 == mQuad1) && (quad2 == mQuad2); } @Override public boolean equals(int[] quads, int qlen) { return (qlen == 2 && quads[0] == mQuad1 && quads[1] == mQuad2); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/package-info.java0000644000175000017500000000022611655120726026140 0ustar jamespagejamespage/** * Internal implementation classes for efficient handling of * of symbols in JSON (field names in Objects) */ package org.codehaus.jackson.sym; jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/Name1.java0000644000175000017500000000202611655120726024555 0ustar jamespagejamespagepackage org.codehaus.jackson.sym; /** * Specialized implementation of PName: can be used for short Strings * that consists of at most 4 bytes. Usually this means short * ascii-only names. *

* The reason for such specialized classes is mostly space efficiency; * and to a lesser degree performance. Both are achieved for short * Strings by avoiding another level of indirection (via quad arrays) */ public final class Name1 extends Name { final static Name1 sEmptyName = new Name1("", 0, 0); final int mQuad; Name1(String name, int hash, int quad) { super(name, hash); mQuad = quad; } final static Name1 getEmptyName() { return sEmptyName; } @Override public boolean equals(int quad) { return (quad == mQuad); } @Override public boolean equals(int quad1, int quad2) { return (quad1 == mQuad) && (quad2 == 0); } @Override public boolean equals(int[] quads, int qlen) { return (qlen == 1 && quads[0] == mQuad); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/BytesToNameCanonicalizer.java0000644000175000017500000007521511655120726030522 0ustar jamespagejamespagepackage org.codehaus.jackson.sym; import java.util.Arrays; import org.codehaus.jackson.util.InternCache; /** * This class is basically a caching symbol table implementation used for * canonicalizing {@link Name}s, constructed directly from a byte-based * input source. * * @author Tatu Saloranta */ public final class BytesToNameCanonicalizer { protected static final int DEFAULT_TABLE_SIZE = 64; /** * Let's not expand symbol tables past some maximum size; * this should protected against OOMEs caused by large documents * with uniquer (~= random) names. * * @since 1.5 */ protected static final int MAX_TABLE_SIZE = 0x10000; // 64k entries == 256k mem /** * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k; * this corresponds to 64k main hash index. This should allow for enough distinct * names for almost any case. */ final static int MAX_ENTRIES_FOR_REUSE = 6000; final static int MIN_HASH_SIZE = 16; final static int INITIAL_COLLISION_LEN = 32; /** * Bucket index is 8 bits, and value 0 is reserved to represent * 'empty' status. */ final static int LAST_VALID_BUCKET = 0xFE; /* /********************************************************** /* Linkage, needed for merging symbol tables /********************************************************** */ final BytesToNameCanonicalizer _parent; /* /********************************************************** /* Main table state /********************************************************** */ /** * Whether canonial symbol Strings are to be intern()ed before added * to the table or not */ final boolean _intern; // // // First, global information /** * Total number of Names in the symbol table */ private int _count; // // // Then information regarding primary hash array and its // // // matching Name array /** * Mask used to truncate 32-bit hash value to current hash array * size; essentially, hash array size - 1 (since hash array sizes * are 2^N). */ private int _mainHashMask; /** * Array of 2^N size, which contains combination * of 24-bits of hash (0 to indicate 'empty' slot), * and 8-bit collision bucket index (0 to indicate empty * collision bucket chain; otherwise subtract one from index) */ private int[] _mainHash; /** * Array that contains Name instances matching * entries in _mainHash. Contains nulls for unused * entries. */ private Name[] _mainNames; // // // Then the collision/spill-over area info /** * Array of heads of collision bucket chains; size dynamically */ private Bucket[] _collList; /** * Total number of Names in collision buckets (included in * _count along with primary entries) */ private int _collCount; /** * Index of the first unused collision bucket entry (== size of * the used portion of collision list): less than * or equal to 0xFF (255), since max number of entries is 255 * (8-bit, minus 0 used as 'empty' marker) */ private int _collEnd; // // // Info regarding pending rehashing... /** * This flag is set if, after adding a new entry, it is deemed * that a rehash is warranted if any more entries are to be added. */ private transient boolean _needRehash; /* /********************************************************** /* Sharing, versioning /********************************************************** */ // // // Which of the buffers may be shared (and are copy-on-write)? /** * Flag that indicates whether underlying data structures for * the main hash area are shared or not. If they are, then they * need to be handled in copy-on-write way, i.e. if they need * to be modified, a copy needs to be made first; at this point * it will not be shared any more, and can be modified. *

* This flag needs to be checked both when adding new main entries, * and when adding new collision list queues (i.e. creating a new * collision list head entry) */ private boolean _mainHashShared; private boolean _mainNamesShared; /** * Flag that indicates whether underlying data structures for * the collision list are shared or not. If they are, then they * need to be handled in copy-on-write way, i.e. if they need * to be modified, a copy needs to be made first; at this point * it will not be shared any more, and can be modified. *

* This flag needs to be checked when adding new collision entries. */ private boolean _collListShared; /* /********************************************************** /* Construction, merging /********************************************************** */ public static BytesToNameCanonicalizer createRoot() { return new BytesToNameCanonicalizer(DEFAULT_TABLE_SIZE, true); } /** * @param intern Whether canonical symbol Strings should be interned * or not */ public synchronized BytesToNameCanonicalizer makeChild(boolean canonicalize, boolean intern) { return new BytesToNameCanonicalizer(this, intern); } /** * Method called by the using code to indicate it is done * with this instance. This lets instance merge accumulated * changes into parent (if need be), safely and efficiently, * and without calling code having to know about parent * information */ public void release() { if (maybeDirty() && _parent != null) { _parent.mergeChild(this); /* Let's also mark this instance as dirty, so that just in * case release was too early, there's no corruption * of possibly shared data. */ markAsShared(); } } private BytesToNameCanonicalizer(int hashSize, boolean intern) { _parent = null; _intern = intern; /* Sanity check: let's now allow hash sizes below certain * min. value */ if (hashSize < MIN_HASH_SIZE) { hashSize = MIN_HASH_SIZE; } else { /* Also; size must be 2^N; otherwise hash algorithm won't * work... so let's just pad it up, if so */ if ((hashSize & (hashSize - 1)) != 0) { // only true if it's 2^N int curr = MIN_HASH_SIZE; while (curr < hashSize) { curr += curr; } hashSize = curr; } } initTables(hashSize); } /** * Constructor used when creating a child instance */ private BytesToNameCanonicalizer(BytesToNameCanonicalizer parent, boolean intern) { _parent = parent; _intern = intern; // First, let's copy the state as is: _count = parent._count; _mainHashMask = parent._mainHashMask; _mainHash = parent._mainHash; _mainNames = parent._mainNames; _collList = parent._collList; _collCount = parent._collCount; _collEnd = parent._collEnd; _needRehash = false; // And consider all shared, so far: _mainHashShared = true; _mainNamesShared = true; _collListShared = true; } private void initTables(int hashSize) { _count = 0; _mainHash = new int[hashSize]; _mainNames = new Name[hashSize]; _mainHashShared = false; _mainNamesShared = false; _mainHashMask = hashSize - 1; _collListShared = true; // just since it'll need to be allocated _collList = null; _collEnd = 0; _needRehash = false; } private synchronized void mergeChild(BytesToNameCanonicalizer child) { // Only makes sense if child has more entries int childCount = child._count; if (childCount <= _count) { return; } /* One caveat: let's try to avoid problems with * degenerate cases of documents with generated "random" * names: for these, symbol tables would bloat indefinitely. * One way to do this is to just purge tables if they grow * too large, and that's what we'll do here. */ if (child.size() > MAX_ENTRIES_FOR_REUSE) { /* Should there be a way to get notified about this * event, to log it or such? (as it's somewhat abnormal * thing to happen) */ // At any rate, need to clean up the tables, then: initTables(DEFAULT_TABLE_SIZE); } else { _count = child._count; _mainHash = child._mainHash; _mainNames = child._mainNames; _mainHashShared = true; // shouldn't matter for parent _mainNamesShared = true; // - "" - _mainHashMask = child._mainHashMask; _collList = child._collList; _collCount = child._collCount; _collEnd = child._collEnd; } } private void markAsShared() { _mainHashShared = true; _mainNamesShared = true; _collListShared = true; } /* /********************************************************** /* API, accessors /********************************************************** */ public int size() { return _count; } /** * Method called to check to quickly see if a child symbol table * may have gotten additional entries. Used for checking to see * if a child table should be merged into shared table. */ public boolean maybeDirty() { return !_mainHashShared; } public static Name getEmptyName() { return Name1.getEmptyName(); } /** * Finds and returns name matching the specified symbol, if such * name already exists in the table. * If not, will return null. *

* Note: separate methods to optimize common case of * short element/attribute names (4 or less ascii characters) * * @param firstQuad int32 containing first 4 bytes of the name; * if the whole name less than 4 bytes, padded with zero bytes * in front (zero MSBs, ie. right aligned) * * @return Name matching the symbol passed (or constructed for * it) */ public Name findName(int firstQuad) { int hash = calcHash(firstQuad); int ix = (hash & _mainHashMask); int val = _mainHash[ix]; /* High 24 bits of the value are low 24 bits of hash (low 8 bits * are bucket index)... match? */ if ((((val >> 8) ^ hash) << 8) == 0) { // match // Ok, but do we have an actual match? Name name = _mainNames[ix]; if (name == null) { // main slot empty; can't find return null; } if (name.equals(firstQuad)) { return name; } } else if (val == 0) { // empty slot? no match return null; } // Maybe a spill-over? val &= 0xFF; if (val > 0) { // 0 means 'empty' val -= 1; // to convert from 1-based to 0... Bucket bucket = _collList[val]; if (bucket != null) { return bucket.find(hash, firstQuad, 0); } } // Nope, no match whatsoever return null; } /** * Finds and returns name matching the specified symbol, if such * name already exists in the table. * If not, will return null. *

* Note: separate methods to optimize common case of relatively * short element/attribute names (8 or less ascii characters) * * @param firstQuad int32 containing first 4 bytes of the name. * @param secondQuad int32 containing bytes 5 through 8 of the * name; if less than 8 bytes, padded with up to 3 zero bytes * in front (zero MSBs, ie. right aligned) * * @return Name matching the symbol passed (or constructed for * it) */ public Name findName(int firstQuad, int secondQuad) { int hash = calcHash(firstQuad, secondQuad); int ix = (hash & _mainHashMask); int val = _mainHash[ix]; /* High 24 bits of the value are low 24 bits of hash (low 8 bits * are bucket index)... match? */ if ((((val >> 8) ^ hash) << 8) == 0) { // match // Ok, but do we have an actual match? Name name = _mainNames[ix]; if (name == null) { // main slot empty; can't find return null; } if (name.equals(firstQuad, secondQuad)) { return name; } } else if (val == 0) { // empty slot? no match return null; } // Maybe a spill-over? val &= 0xFF; if (val > 0) { // 0 means 'empty' val -= 1; // to convert from 1-based to 0... Bucket bucket = _collList[val]; if (bucket != null) { return bucket.find(hash, firstQuad, secondQuad); } } // Nope, no match whatsoever return null; } /** * Finds and returns name matching the specified symbol, if such * name already exists in the table; or if not, creates name object, * adds to the table, and returns it. *

* Note: this is the general purpose method that can be called for * names of any length. However, if name is less than 9 bytes long, * it is preferable to call the version optimized for short * names. * * @param quads Array of int32s, each of which contain 4 bytes of * encoded name * @param qlen Number of int32s, starting from index 0, in quads * parameter * * @return Name matching the symbol passed (or constructed for it) */ public Name findName(int[] quads, int qlen) { /* // Not needed, never gets called if (qlen < 3) { // another sanity check return findName(quads[0], (qlen < 2) ? 0 : quads[1]); } */ int hash = calcHash(quads, qlen); // (for rest of comments regarding logic, see method above) int ix = (hash & _mainHashMask); int val = _mainHash[ix]; if ((((val >> 8) ^ hash) << 8) == 0) { Name name = _mainNames[ix]; if (name == null // main slot empty; no collision list then either || name.equals(quads, qlen)) { // should be match, let's verify return name; } } else if (val == 0) { // empty slot? no match return null; } val &= 0xFF; if (val > 0) { // 0 means 'empty' val -= 1; // to convert from 1-based to 0... Bucket bucket = _collList[val]; if (bucket != null) { return bucket.find(hash, quads, qlen); } } return null; } /* /********************************************************** /* API, mutators /********************************************************** */ /** * @since 1.6.0 */ public Name addName(String symbolStr, int q1, int q2) { if (_intern) { symbolStr = InternCache.instance.intern(symbolStr); } int hash = (q2 == 0) ? calcHash(q1) : calcHash(q1, q2); Name symbol = constructName(hash, symbolStr, q1, q2); _addSymbol(hash, symbol); return symbol; } public Name addName(String symbolStr, int[] quads, int qlen) { if (_intern) { symbolStr = InternCache.instance.intern(symbolStr); } int hash = calcHash(quads, qlen); Name symbol = constructName(hash, symbolStr, quads, qlen); _addSymbol(hash, symbol); return symbol; } /* /********************************************************** /* Helper methods /********************************************************** */ public final static int calcHash(int firstQuad) { int hash = firstQuad; hash ^= (hash >>> 16); // to xor hi- and low- 16-bits hash ^= (hash >>> 8); // as well as lowest 2 bytes return hash; } public final static int calcHash(int firstQuad, int secondQuad) { int hash = (firstQuad * 31) + secondQuad; // If this was called for single-quad instance: //int hash = (secondQuad == 0) ? firstQuad : ((firstQuad * 31) + secondQuad); hash ^= (hash >>> 16); // to xor hi- and low- 16-bits hash ^= (hash >>> 8); // as well as lowest 2 bytes return hash; } public final static int calcHash(int[] quads, int qlen) { // Note: may be called for qlen < 3 int hash = quads[0]; for (int i = 1; i < qlen; ++i) { hash = (hash * 31) + quads[i]; } hash ^= (hash >>> 16); // to xor hi- and low- 16-bits hash ^= (hash >>> 8); // as well as lowest 2 bytes return hash; } /* 26-Nov-2008, tatu: not used currently; if not used in near future, * let's just delete it. */ /* public static int[] calcQuads(byte[] wordBytes) { int blen = wordBytes.length; int[] result = new int[(blen + 3) / 4]; for (int i = 0; i < blen; ++i) { int x = wordBytes[i] & 0xFF; if (++i < blen) { x = (x << 8) | (wordBytes[i] & 0xFF); if (++i < blen) { x = (x << 8) | (wordBytes[i] & 0xFF); if (++i < blen) { x = (x << 8) | (wordBytes[i] & 0xFF); } } } result[i >> 2] = x; } return result; } */ /* /********************************************************** /* Standard methods /********************************************************** */ /* @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("[BytesToNameCanonicalizer, size: "); sb.append(_count); sb.append('/'); sb.append(_mainHash.length); sb.append(", "); sb.append(_collCount); sb.append(" coll; avg length: "); // Average length: minimum of 1 for all (1 == primary hit); // and then 1 per each traversal for collisions/buckets //int maxDist = 1; int pathCount = _count; for (int i = 0; i < _collEnd; ++i) { int spillLen = _collList[i].length(); for (int j = 1; j <= spillLen; ++j) { pathCount += j; } } double avgLength; if (_count == 0) { avgLength = 0.0; } else { avgLength = (double) pathCount / (double) _count; } // let's round up a bit (two 2 decimal places) //avgLength -= (avgLength % 0.01); sb.append(avgLength); sb.append(']'); return sb.toString(); } */ /* /********************************************************** /* Internal methods /********************************************************** */ private void _addSymbol(int hash, Name symbol) { if (_mainHashShared) { // always have to modify main entry unshareMain(); } // First, do we need to rehash? if (_needRehash) { rehash(); } ++_count; /* Ok, enough about set up: now we need to find the slot to add * symbol in: */ int ix = (hash & _mainHashMask); if (_mainNames[ix] == null) { // primary empty? _mainHash[ix] = (hash << 8); if (_mainNamesShared) { unshareNames(); } _mainNames[ix] = symbol; } else { // nope, it's a collision, need to spill over /* How about spill-over area... do we already know the bucket * (is the case if it's not the first collision) */ if (_collListShared) { unshareCollision(); // also allocates if list was null } ++_collCount; int entryValue = _mainHash[ix]; int bucket = entryValue & 0xFF; if (bucket == 0) { // first spill over? if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket bucket = _collEnd; ++_collEnd; // need to expand? if (bucket >= _collList.length) { expandCollision(); } } else { // nope, have to share... let's find shortest? bucket = findBestBucket(); } // Need to mark the entry... and the spill index is 1-based _mainHash[ix] = (entryValue & ~0xFF) | (bucket + 1); } else { --bucket; // 1-based index in value } // And then just need to link the new bucket entry in _collList[bucket] = new Bucket(symbol, _collList[bucket]); } /* Ok. Now, do we need a rehash next time? Need to have at least * 50% fill rate no matter what: */ { int hashSize = _mainHash.length; if (_count > (hashSize >> 1)) { int hashQuarter = (hashSize >> 2); /* And either strictly above 75% (the usual) or * just 50%, and collision count >= 25% of total hash size */ if (_count > (hashSize - hashQuarter)) { _needRehash = true; } else if (_collCount >= hashQuarter) { _needRehash = true; } } } } private void rehash() { _needRehash = false; // Note: since we'll make copies, no need to unshare, can just mark as such: _mainNamesShared = false; /* And then we can first deal with the main hash area. Since we * are expanding linearly (double up), we know there'll be no * collisions during this phase. */ int[] oldMainHash = _mainHash; int len = oldMainHash.length; int newLen = len+len; /* 13-Mar-2010, tatu: Let's guard against OOME that could be caused by * large documents with unique (or mostly so) names */ if (newLen > MAX_TABLE_SIZE) { nukeSymbols(); return; } _mainHash = new int[newLen]; _mainHashMask = (newLen - 1); Name[] oldNames = _mainNames; _mainNames = new Name[newLen]; int symbolsSeen = 0; // let's do a sanity check for (int i = 0; i < len; ++i) { Name symbol = oldNames[i]; if (symbol != null) { ++symbolsSeen; int hash = symbol.hashCode(); int ix = (hash & _mainHashMask); _mainNames[ix] = symbol; _mainHash[ix] = hash << 8; // will clear spill index } } /* And then the spill area. This may cause collisions, although * not necessarily as many as there were earlier. Let's allocate * same amount of space, however */ int oldEnd = _collEnd; if (oldEnd == 0) { // no prior collisions... return; } _collCount = 0; _collEnd = 0; _collListShared = false; Bucket[] oldBuckets = _collList; _collList = new Bucket[oldBuckets.length]; for (int i = 0; i < oldEnd; ++i) { for (Bucket curr = oldBuckets[i]; curr != null; curr = curr._next) { ++symbolsSeen; Name symbol = curr._name; int hash = symbol.hashCode(); int ix = (hash & _mainHashMask); int val = _mainHash[ix]; if (_mainNames[ix] == null) { // no primary entry? _mainHash[ix] = (hash << 8); _mainNames[ix] = symbol; } else { // nope, it's a collision, need to spill over ++_collCount; int bucket = val & 0xFF; if (bucket == 0) { // first spill over? if (_collEnd <= LAST_VALID_BUCKET) { // yup, still unshared bucket bucket = _collEnd; ++_collEnd; // need to expand? if (bucket >= _collList.length) { expandCollision(); } } else { // nope, have to share... let's find shortest? bucket = findBestBucket(); } // Need to mark the entry... and the spill index is 1-based _mainHash[ix] = (val & ~0xFF) | (bucket + 1); } else { --bucket; // 1-based index in value } // And then just need to link the new bucket entry in _collList[bucket] = new Bucket(symbol, _collList[bucket]); } } // for (... buckets in the chain ...) } // for (... list of bucket heads ... ) if (symbolsSeen != _count) { // sanity check throw new RuntimeException("Internal error: count after rehash "+symbolsSeen+"; should be "+_count); } } /** * Helper method called to empty all shared symbols, but to leave * arrays allocated */ private void nukeSymbols() { _count = 0; Arrays.fill(_mainHash, 0); Arrays.fill(_mainNames, null); Arrays.fill(_collList, null); _collCount = 0; _collEnd = 0; } /** * Method called to find the best bucket to spill a Name over to: * usually the first bucket that has only one entry, but in general * first one of the buckets with least number of entries */ private int findBestBucket() { Bucket[] buckets = _collList; int bestCount = Integer.MAX_VALUE; int bestIx = -1; for (int i = 0, len = _collEnd; i < len; ++i) { int count = buckets[i].length(); if (count < bestCount) { if (count == 1) { // best possible return i; } bestCount = count; bestIx = i; } } return bestIx; } /** * Method that needs to be called, if the main hash structure * is (may be) shared. This happens every time something is added, * even if addition is to the collision list (since collision list * index comes from lowest 8 bits of the primary hash entry) */ private void unshareMain() { int[] old = _mainHash; int len = _mainHash.length; _mainHash = new int[len]; System.arraycopy(old, 0, _mainHash, 0, len); _mainHashShared = false; } private void unshareCollision() { Bucket[] old = _collList; if (old == null) { _collList = new Bucket[INITIAL_COLLISION_LEN]; } else { int len = old.length; _collList = new Bucket[len]; System.arraycopy(old, 0, _collList, 0, len); } _collListShared = false; } private void unshareNames() { Name[] old = _mainNames; int len = old.length; _mainNames = new Name[len]; System.arraycopy(old, 0, _mainNames, 0, len); _mainNamesShared = false; } private void expandCollision() { Bucket[] old = _collList; int len = old.length; _collList = new Bucket[len+len]; System.arraycopy(old, 0, _collList, 0, len); } /* /********************************************************** /* Constructing name objects /********************************************************** */ private static Name constructName(int hash, String name, int q1, int q2) { if (q2 == 0) { // one quad only? return new Name1(name, hash, q1); } return new Name2(name, hash, q1, q2); } private static Name constructName(int hash, String name, int[] quads, int qlen) { if (qlen < 4) { // Need to check for 3 quad one, can do others too switch (qlen) { case 1: return new Name1(name, hash, quads[0]); case 2: return new Name2(name, hash, quads[0], quads[1]); case 3: return new Name3(name, hash, quads[0], quads[1], quads[2]); default: } } // Otherwise, need to copy the incoming buffer int[] buf = new int[qlen]; for (int i = 0; i < qlen; ++i) { buf[i] = quads[i]; } return new NameN(name, hash, buf, qlen); } /* /********************************************************** /* Helper classes /********************************************************** */ final static class Bucket { protected final Name _name; protected final Bucket _next; Bucket(Name name, Bucket next) { _name = name; _next = next; } public int length() { int len = 1; for (Bucket curr = _next; curr != null; curr = curr._next) { ++len; } return len; } public Name find(int hash, int firstQuad, int secondQuad) { if (_name.hashCode() == hash) { if (_name.equals(firstQuad, secondQuad)) { return _name; } } for (Bucket curr = _next; curr != null; curr = curr._next) { Name currName = curr._name; if (currName.hashCode() == hash) { if (currName.equals(firstQuad, secondQuad)) { return currName; } } } return null; } public Name find(int hash, int[] quads, int qlen) { if (_name.hashCode() == hash) { if (_name.equals(quads, qlen)) { return _name; } } for (Bucket curr = _next; curr != null; curr = curr._next) { Name currName = curr._name; if (currName.hashCode() == hash) { if (currName.equals(quads, qlen)) { return currName; } } } return null; } } } jackson-src-1.9.2/src/java/org/codehaus/jackson/sym/Name3.java0000644000175000017500000000171611655120726024564 0ustar jamespagejamespagepackage org.codehaus.jackson.sym; /** * Specialized implementation of PName: can be used for short Strings * that consists of 9 to 12 bytes. It's the longest special purpose * implementaion; longer ones are expressed using {@link NameN}. */ public final class Name3 extends Name { final int mQuad1; final int mQuad2; final int mQuad3; Name3(String name, int hash, int q1, int q2, int q3) { super(name, hash); mQuad1 = q1; mQuad2 = q2; mQuad3 = q3; } // Implies quad length == 1, never matches @Override public boolean equals(int quad) { return false; } // Implies quad length == 2, never matches @Override public boolean equals(int quad1, int quad2) { return false; } @Override public boolean equals(int[] quads, int qlen) { return (qlen == 3) && (quads[0] == mQuad1) && (quads[1] == mQuad2) && (quads[2] == mQuad3); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/Versioned.java0000644000175000017500000000143311655120726024743 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Interface that those Jackson components that are explicitly versioned will implement. * Intention is to allow both plug-in components (custom extensions) and applications and * frameworks that use Jackson to detect exact version of Jackson in use. * This may be useful for example for ensuring that proper Jackson version is deployed * (beyond mechanisms that deployment system may have), as well as for possible * workarounds. * * @since 1.6 */ public interface Versioned { /** * Method called to detect version of the component that implements this interface; * returned version should never be null, but may return specific "not available" * instance (see {@link Version} for details). */ public Version version(); } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/0000755000175000017500000000000011672662540023756 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JacksonAnnotation.java0000644000175000017500000000121411655120726030236 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Meta-annotation (annotations used on other annotations) * used for marking all annotations that are * part of Jackson package. Can be used for recognizing all * Jackson annotations generically, and in future also for * passing other generic annotation configuration. */ @Target({ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface JacksonAnnotation { // for now, a pure tag annotation, no parameters } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonIgnoreType.java0000644000175000017500000000206711655120726027541 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that indicates that all properties of annotated * type are to be ignored during serialization and deserialization. *

* Note: annotation does have boolean 'value' property (which defaults * to 'true'), so that it is actually possible to override value * using mix-in annotations. * * @since 1.7 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonIgnoreType { /** * Optional argument that defines whether this annotation is active * or not. The only use for value 'false' if for overriding purposes * (which is not needed often); most likely it is needed for use * with "mix-in annotations" ("annotation overrides"). * For most cases, however, default value of "true" is just fine * and should be omitted. */ boolean value() default true; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonPropertyOrder.java0000644000175000017500000000304411655120726030270 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation that can be used to define ordering (possibly partial) to use * when serializing object properties. Properties included in annotation * declaration will be serialized first (in defined order), followed by * any properties not included in the definition. * Annotation definition will override any implicit orderings (such as * guarantee that Creator-properties are serialized before non-creator * properties) *

* Examples: *

 *  // ensure that "id" and "name" are output before other properties
 *  
@
JsonPropertyOrder({ "id", "name" }) * // order any properties that don't have explicit setting using alphabetic order *
@
JsonPropertyOrder(alphabetic=true) *
*

* This annotation has no effect on deserialization. * * @since 1.4 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonPropertyOrder { /** * Order in which properties of annotated object are to be serialized in. */ public String[] value() default { }; /** * Property that defines what to do regarding ordering of properties * not explicitly included in annotation instance. If set to true, * they will be alphabetically ordered; if false, order is * undefined (default setting) */ public boolean alphabetic() default false; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonSetter.java0000644000175000017500000000227311655120726026721 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that can be used to define a non-static, * single-argument method to be used as a "setter" for a logical property * as an alternative to recommended * {@link JsonProperty} annotation (which was introduced in version 1.1). *

* Setter means that when a property with matching name is encountered in * JSON content, this method will be used to set value of the property. *

* NOTE: this annotation was briefly deprecated for version 1.5; but has * since been un-deprecated to both allow for asymmetric naming (possibly * different name when reading and writing JSON), and more importantly to * allow multi-argument setter method in future. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonSetter { /** * Optional default argument that defines logical property this * method is used to modify ("set"); this is the property * name used in JSON content. */ String value() default ""; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonBackReference.java0000644000175000017500000000330111655120726030123 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation used to indicate that associated property is part of * two-way linkage between fields; and that its role is "child" (or "back") link. * Value type of the property must be a bean: it can not be a Collection, Map, * Array or enumeration. * Linkage is handled such that the property * annotated with this annotation is not serialized; and during deserialization, * its value is set to instance that has the "managed" (forward) link. *

* All references have logical name to allow handling multiple linkages; typical case * would be that where nodes have both parent/child and sibling linkages. If so, * pairs of references should be named differently. * It is an error for a class to have multiple back references with same name, * even if types pointed are different. *

* Note: only methods and fields can be annotated with this annotation: constructor * arguments should NOT be annotated, as they can not be either managed or back * references. * * @author tatu */ @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonBackReference { /** * Logical have for the reference property pair; used to link managed and * back references. Default name can be used if there is just single * reference pair (for example, node class that just has parent/child linkage, * consisting of one managed reference and matching back reference) */ public String value() default "defaultReference"; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonAnySetter.java0000644000175000017500000000144311655120726027367 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that can be used to define a non-static, * single-argument method, to be used as a "fallback" handler * for all otherwise unrecognized properties found from Json content. * It is similar to {@link javax.xml.bind.annotation.XmlAnyElement} * in behavior; and can only be used to denote a single property * per type. *

* If used, all otherwise unmapped key-value pairs from Json Object * structs are added to the property (of type Map or bean). */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonAnySetter { } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonGetter.java0000644000175000017500000000225711655120726026707 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that can be used to define a non-static, * no-argument value-returning (non-void) method to be used as a "getter" * for a logical property, * as an alternative to recommended * {@link JsonProperty} annotation (which was introduced in version 1.1). *

* Getter means that when serializing Object instance of class that has * this method (possibly inherited from a super class), a call is made * through the method, and return value will be serialized as value of * the property. * * @deprecated Use {@link JsonProperty} instead (deprecated since version 1.5) */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation @Deprecated public @interface JsonGetter { /** * Defines name of the logical property this * method is used to access ("get"); empty String means that * name should be derived from the underlying method (using * standard Bean name detection rules) */ String value() default ""; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonIgnore.java0000644000175000017500000000372411655120726026700 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation * that indicates that the annotated method or field is to be ignored by * introspection-based * serialization and deserialization functionality. That is, it should * not be consider a "getter", "setter" or "creator". *

* For example, * a "getter" method that would otherwise denote * a property (like, say, "getValue" to suggest property "value") * to serialize, would be ignored and no such property would * be output unless another annotation defines alternative method * to use. *

* This annotation works purely on method-by-method (or field-by-field) basis; * annotation on one method or field does not imply ignoring other methods * or fields. * Specifically, marking a "setter" candidate does not change handling * of matching "getter" method (or vice versa). *

* Annotation is usually used just a like a marker annotation, that * is, without explicitly defining 'value' argument (which defaults * to true): but argument can be explicitly defined. * This can be done to override an existing JsonIgnore by explictly * defining one with 'false' argument. *

* Annotation is similar to {@link javax.xml.bind.annotation.XmlTransient} */ @Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonIgnore { /** * Optional argument that defines whether this annotation is active * or not. The only use for value 'false' if for overriding purposes * (which is not needed often); most likely it is needed for use * with "mix-in annotations" (aka "annotation overrides"). * For most cases, however, default value of "true" is just fine * and should be omitted. */ boolean value() default true; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonRawValue.java0000644000175000017500000000231311655120726027174 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that indicates that the annotated method * or field should be serialized by including literal String value * of the property as is, without quoting of characters. * This can be useful for injecting values already serialized in JSON or * passing javascript function definitions from server to a javascript client. *

* Warning: the resulting JSON stream may be invalid depending on your input value. * * @since 1.7.0 */ @Target( { ElementType.METHOD, ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonRawValue { /** * Optional argument that defines whether this annotation is active * or not. The only use for value 'false' if for overriding purposes * (which is not needed often); most likely it is needed for use * with "mix-in annotations" (aka "annotation overrides"). * For most cases, however, default value of "true" is just fine * and should be omitted. */ boolean value() default true; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonWriteNullProperties.java0000644000175000017500000000217511655120726031456 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation that can be used to define whether object properties * that have null values are to be written out when serializing * content as JSON. This affects Bean and Map serialization. *

* Annotation can be used with Classes (all instances of * given class) and Methods. *

* Default value for this property is 'true', meaning that null * properties are written. *

* @deprecated (since 1.6) Currently recommended annotation to use is * {@link org.codehaus.jackson.map.annotate.JsonSerialize#include()} * (with values ALWAYS or NON_NULL) */ @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation @Deprecated public @interface JsonWriteNullProperties { /** * Whether properties for beans of annotated type will always be * written (true), or only if not null (false). */ boolean value() default true; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonSubTypes.java0000644000175000017500000000305011655120726027223 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation used with {@link JsonTypeInfo} to indicate sub types of serializable * polymorphic types, and to associate logical names used within JSON content * (which is more portable than using physical Java class names). * * @since 1.5 (but available to fields, methods and constructor params only since 1.8) */ @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonSubTypes { /** * Subtypes of the annotated type (annotated class, or property value type * associated with the annotated method). These will be checked recursively * so that types can be defined by only including direct subtypes. */ public Type[] value(); /** * Definition of a subtype, along with optional name. If name is missing, class * of the type will be checked for {@link JsonTypeName} annotation; and if that * is also missing or empty, a default * name will be constructed by type id mechanism. * Default name is usually based on class name. */ public @interface Type { /** * Class of the subtype */ public Class value(); /** * Logical type name used as the type identifier for the class */ public String name() default ""; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonTypeInfo.java0000644000175000017500000002226111655120726027207 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.*; /** * Annotation used for configuring details of if and how type information is * used with JSON serialization and deserialization, to preserve information * about actual class of Object instances. This is necessarily for polymorphic * types, and may also be needed to link abstract declared types and matching * concrete implementation. *

* Some examples of typical annotations: *

 *  // Include Java class name ("com.myempl.ImplClass") as JSON property "class"
 *  @JsonTypeInfo(use=Id.CLASS, include=As.PROPERTY, property="class")
 *  
 *  // Include logical type name (defined in impl classes) as wrapper; 2 annotations
 *  @JsonTypeInfo(use=Id.NAME, include=As.WRAPPER_OBJECT)
 *  @JsonSubTypes({com.myemp.Impl1.class, com.myempl.Impl2.class})
 *
* Alternatively you can also define fully customized type handling by using * {@link org.codehaus.jackson.map.annotate.JsonTypeResolver} annotation. *

* NOTE: originally this annotation was only available to use with types (classes), * but starting with 1.7, it is also allowed for properties (fields, methods, * constructor parameters). *

* When used for properties (fields, methods), there annotation always defines * to values: specifically, when applied to a Collection or * Map property, it will not apply to container type but * to contained values. This is identical to how JAXB handles type information * annotations; and is chosen since it is the dominant use case. There is no * per-property way to force type information to be included for type of * container itself. * * @see org.codehaus.jackson.map.annotate.JsonTypeResolver * * @since 1.5 (but available to fields, methods and constructor params since 1.7) * * @author tatu */ @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonTypeInfo { /* /********************************************************** /* Value enumerations used for properties /********************************************************** */ /** * Definition of different type identifiers that can be included in JSON * during serialization, and used for deserialization. */ public enum Id { /** * This means that no explicit type metadata is included, and typing is * purely done using contextual information possibly augmented with other * annotations. *

* Note: no {@link org.codehaus.jackson.map.jsontype.TypeIdResolver} * is constructed if this value is used. */ NONE(null), /** * Means that fully-qualified Java class name is used as the type identifier. */ CLASS("@class"), /** * Means that Java class name with minimal path is used as the type identifier. * Minimal means that only the class name, and that part of preceding Java * package name is included that is needed to construct fully-qualified name * given fully-qualified name of the declared supertype; additionally a single * leading dot ('.') must be used to indicate that partial class name is used. * For example, for supertype "com.foobar.Base", and concrete type * "com.foo.Impl", only ".Impl" would be included; and for "com.foo.impl.Impl2" * only ".impl.Impl2" would be included.
* NOTE: leading dot ('.') MUST be used to denote partial (minimal) name; * if it is missing, value is assumed to be fully-qualified name. Fully-qualified * name is used in cases where subtypes are not in same package (or sub-package * thereof) as base class. *

* If all related classes are in the same Java package, this option can reduce * amount of type information overhead, especially for small types. * However, please note that using this alternative is inherently risky since it * assumes that the * supertype can be reliably detected. Given that it is based on declared type * (since ultimate supertype, java.lang.Object would not be very * useful reference point), this may not always work as expected. */ MINIMAL_CLASS("@c"), /** * Means that logical type name is used as type information; name will then need * to be separately resolved to actual concrete type (Class). */ NAME("@type"), /** * Means that typing mechanism uses customized handling, with possibly * custom configuration. This means that semantics of other properties is * not defined by Jackson package, but by the custom implementation. */ CUSTOM(null) ; private final String _defaultPropertyName; private Id(String defProp) { _defaultPropertyName = defProp; } public String getDefaultPropertyName() { return _defaultPropertyName; } } /** * Definition of standard type inclusion mechanisms for type metadata. * Used for standard metadata types, except for {@link Id#NONE}. * May or may not be used for custom types ({@link Id#CUSTOM}). */ public enum As { /** * Inclusion mechanism that uses a single configurable property, included * along with actual data (POJO properties) as a separate meta-property. *

* Default choice for inclusion. */ PROPERTY, /** * Inclusion mechanism that wraps typed JSON value (POJO * serialized as JSON) in * a JSON Object that has a single entry, * where field name is serialized type identifier, * and value is the actual JSON value. *

* Note: can only be used if type information can be serialized as * String. This is true for standard type metadata types, but not * necessarily for custom types. */ WRAPPER_OBJECT, /** * Inclusion mechanism that wraps typed JSON value (POJO * serialized as JSON) in * a 2-element JSON array: first element is the serialized * type identifier, and second element the serialized POJO * as JSON Object. */ WRAPPER_ARRAY, /** * Inclusion mechanism similar to PROPERTY, except that * property is included one-level higher in hierarchy, i.e. as sibling * property at same level as JSON Object to type. * Note that this choice can only be used for properties, not * for types (classes). Trying to use it for classes will result in * inclusion strategy of basic PROPERTY instead. * * @since 1.9 */ EXTERNAL_PROPERTY ; } /* /********************************************************** /* Annotation properties /********************************************************** */ /** * What kind of type metadata is to be used for serializing and deserializing * type information for instances of annotated type (and its subtypes * unless overridden) */ public Id use(); /** * What mechanism is used for including type metadata (if any; for * {@link Id#NONE} nothing is included). Default *

* Note that for type metadata type of {@link Id#CUSTOM}, * this setting may or may not have any effect. */ public As include() default As.PROPERTY; /** * Property names used when type inclusion method ({@link As#PROPERTY}) is used * (or possibly when using type metadata of type {@link Id#CUSTOM}). *

* Default property name used if this property is not explicitly defined * (or is set to empty String) is based on * type metadata type ({@link #use}) used. */ public String property() default ""; /** * Optional property that can be used to specify default implementation * class to use if type identifier is either not present, or can not * be mapped to a registered type (which can occur for ids, but not when * specifying explicit class to use). *

* Note that while this property allows specification of the default * implementation to use, it does not help with structural issues that * may arise if type information is missing. This means that most often * this is used with type-name -based resolution, to cover cases * where new sub-types are added, but base type is not changed to * reference new sub-types. * * @since 1.9 */ public Class defaultImpl() default None.class; /* /********************************************************** /* Helper classes /********************************************************** */ /** * This marker class that is only to be used with defaultImpl * annotation property, to indicate that there is no default implementation * specified. * * @since 1.9 */ public abstract static class None { } } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/package-info.java0000644000175000017500000000146611655120726027150 0ustar jamespagejamespage/** * Public core annotations, most of which are used to configure how * Data Mapping/Binding works. Annotations in this package can only * have dependencies to non-annotation classes in Core package; * annotations that have dependencies to Mapper classes are included * in Mapper module (under org.codehaus.jackson.map.annotate). * Also contains parameter types (mostly enums) needed by annotations. *

* In future (version 2.0?), this package will probably be split off * as a separate jar/module, to allow use of annotations without * including core module. This would be useful for third party value * classes that themselves do not depend on Jackson, but may want to * be annotated to be automatically and conveniently serializable by * Jackson. */ package org.codehaus.jackson.annotate; jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonCreator.java0000644000175000017500000000105411655120726027046 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that can be used to define constructors and factory * methods as one to use for instantiating new instances of the associated * class. */ @Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonCreator { // no values, since there's no property } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonTypeName.java0000644000175000017500000000143511655120726027174 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation used for binding logical name that the annotated class * has. Used with {@link JsonTypeInfo} (and specifically its * {@link JsonTypeInfo#use} property) to establish relationship * between type names and types. * * @since 1.5 * * @author tatu */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonTypeName { /** * Logical type name for annotated type. If missing (or defined as Empty String), * defaults to using non-qualified class name as the type. */ public String value() default ""; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonUnwrapped.java0000644000175000017500000000401111655120726027410 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation used to indicate that a property should be serialized * "unwrapped"; that is, if it would be serialized as JSON Object, its * properties are instead included as properties of its containing * Object. For example, consider case of POJO like: * *

 *  public class Parent {
 *    public int age;
 *    public Name name;
 *  }
 *  public class Name {
 *    public String first, last;
 *  }
 *
* which would normally be serialized as follows (assuming @JsonUnwrapped * had no effect): *
 *  {
 *    "age" : 18,
 *    "name" : {
 *      "first" : "Joey",
 *      "last" : "Sixpack"
 *    }
 *  }
 *
* can be changed to this: *
 *  {
 *    "age" : 18,
 *    "first" : "Joey",
 *    "last" : "Sixpack"
 *  }
 *
* by changing Parent class to: *
 *  public class Parent {
 *    public int age;
 *    \@JsonUnwrapped
 *    public Name name;
 *  }
 *
* Annotation can only be added to properties, and not classes, as it is contextual. *

* Also note that annotation only applies if *

    *
  • Value is serialized as JSON Object *
  • *
  • Serialization is done using BeanSerializer, not a custom serializer *
  • *
  • No type information is added; if type information needs to be added, structure can * not be altered regardless of inclusion strategy; so annotation is basically ignored. *
  • *
* * @since 1.9 */ @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonUnwrapped { /** * Property that is usually only used when overriding (masking) annotations, * using mix-in annotations. Otherwise default value of 'true' is fine, and * value need not be explicitly included. */ boolean enabled() default true; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonValue.java0000644000175000017500000000345411655120726026531 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation similar to * {@link javax.xml.bind.annotation.XmlValue} * that indicates that results of the annotated "getter" method * (which means signature must be that of getters; non-void return * type, no args) is to be used as the single value to serialize * for the instance. Usually value will be of a simple scalar type * (String or Number), but it can be any serializable type (Collection, * Map or Bean). *

* At most one method of a Class can be annotated with this annotation; * if more than one is found, an exception may be thrown. * Also, if method signature is not compatible with Getters, an exception * may be thrown. * Whether exception is thrown or not is an implementation detail (due * to filtering during introspection, some annotations may be skipped) * and applications should not rely on specific behavior. *

* A typical use case is that of annotating toString() * method so that returned String value is Object's Json serialization. *

* Boolean argument is only used so that sub-classes can "disable" * annotation if necessary. */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonValue { /** * Optional argument that defines whether this annotation is active * or not. The only use for value 'false' if for overriding purposes. * Overriding may be necessary when used * with "mix-in annotations" (aka "annotation overrides"). * For most cases, however, default value of "true" is just fine * and should be omitted. */ boolean value() default true; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonProperty.java0000644000175000017500000000247511655120726027303 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that can be used to define a non-static * method as a "setter" or "getter" for a logical property * (depending on its signature), * or non-static object field to be used (serialized, deserialized) as * a logical property. *

* Default value ("") indicates that the field name is used * as the property name without any modifications, but it * can be specified to non-empty value to specify different * name. Property name refers to name used externally, as * the field name in Json objects. *

* NOTE: since version 1.1, annotation has also been applicable * to fields (not with 1.0). *

* NOTE: since version 1.2, annotation has also been applicable * to (constructor) parameters */ @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonProperty { /** * Defines name of the logical property, i.e. Json object field * name to use for the property: if empty String (which is the * default), will use name of the field that is annotated. */ String value() default ""; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonAnyGetter.java0000644000175000017500000000152011655120726027347 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Marker annotation that can be used to define a non-static, * no-argument method or member field as something of a reverse of * {@link JsonAnySetter} method; basically being used like a * getter but such that contents of the returned Map (type must be * {@link java.util.Map}) are serialized as if they were actual properties * of the bean that contains method/field with this annotations. * As with {@link JsonAnySetter}, only one property should be annotated * with this annotation. * * @since 1.6 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonAnyGetter { } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonMethod.java0000644000175000017500000000525411655120726026675 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; /** * Enumeration used to define kinds of methods that annotations like * {@link JsonAutoDetect} apply to. *

* In addition to actual method types (GETTER, SETTER, CREATOR; and * sort-of-method, FIELD), 2 pseudo-types * are defined for convenience: ALWAYS and NONE. These * can be used to indicate, all or none of available method types (respectively), * for use by annotations that takes JsonMethod argument. */ public enum JsonMethod { /** * Getters are methods used to get a POJO field value for serialization, * or, under certain conditions also for de-serialization. Latter * can be used for effectively setting Collection or Map values * in absence of setters, iff returned value is not a copy but * actual value of the logical property. *

* Since version 1.3, this does NOT include "is getters" (methods * that return boolean and named 'isXxx' for property 'xxx'); instead, * {@link #IS_GETTER} is used}. */ GETTER, /** * Setters are methods used to set a POJO value for deserialization. */ SETTER, /** * Creators are constructors and (static) factory methods used to * construct POJO instances for deserialization */ CREATOR, /** * Field refers to fields of regular Java objects. Although * they are not really methods, addition of optional field-discovery * in version 1.1 meant that there was need to enable/disable * their auto-detection, and this is the place to add it in. * * @since 1.1 */ FIELD, /** * "Is getters" are getter-like methods that are named "isXxx" * (instead of "getXxx" for getters) and return boolean value * (either primitive, or {@link java.lang.Boolean}). * * @since 1.3 */ IS_GETTER, /** * This pseudo-type indicates that none of real types is included */ NONE, /** * This pseudo-type indicates that all of real types are included */ ALL ; private JsonMethod() { } public boolean creatorEnabled() { return (this == CREATOR) || (this == ALL); } public boolean getterEnabled() { return (this == GETTER) || (this == ALL); } public boolean isGetterEnabled() { return (this == IS_GETTER) || (this == ALL); } public boolean setterEnabled() { return (this == SETTER) || (this == ALL); } public boolean fieldEnabled() { return (this == FIELD) || (this == ALL); } } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonIgnoreProperties.java0000644000175000017500000000306511655120726030753 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation that can be used to either suppress serialization of * properties (during serialization), or ignore processing of * JSON properties read (during deserialization). *

* Example: *

 * // to prevent specified fields from being serialized or deserialized
 * // (i.e. not include in JSON output; or being set even if they were included)
 * \@JsonIgnoreProperties({ "internalId", "secretKey" })
 * // To ignore any unknown properties in JSON input without exception:
 * \@JsonIgnoreProperties(ignoreUnknown=true)
 *
*

* Only applicable to classes, not for properties (getters, setters, fields). * * @since 1.4 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonIgnoreProperties { /** * Names of properties to ignore. */ public String[] value() default { }; /** * Property that defines whether it is ok to just ignore any * unrecognized properties during deserialization. * If true, all properties that are unrecognized -- that is, * there are no setters or creators that accept them -- are * ignored without warnings (although handlers for unknown * properties, if any, will still be called) without * exception. *

* Does not have any effect on serialization. */ public boolean ignoreUnknown() default false; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonAutoDetect.java0000644000175000017500000001123611655120726027513 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Member; import java.lang.reflect.Modifier; /** * Class annotation that can be used to define which kinds of Methods * are to be detected by auto-detection. * Auto-detection means using name conventions * and/or signature templates to find methods to use for data binding. * For example, so-called "getters" can be auto-detected by looking for * public member methods that return a value, do not take argument, * and have prefix "get" in their name. *

* Pseudo-value NONE means that all auto-detection is disabled * for the specific class that annotation is applied to (including * its super-types, but only when resolving that class). * Pseudo-value ALWAYS means that auto-detection is enabled * for all method types for the class in similar way. *

* The default value is ALWAYS: that is, by default, auto-detection * is enabled for all classes unless instructed otherwise. *

* Starting with version 1.5, it is also possible to use more fine-grained * definitions, to basically define minimum visibility level needed. Defaults * are different for different types (getters need to be public; setters can * have any access modifier, for example). */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonAutoDetect { /** * Enumeration for possible visibility thresholds (minimum visibility) * that can be used to limit which methods (and fields) are * auto-detected. * * @since 1.5 */ public enum Visibility { /** * Value that means that all kinds of access modifiers are acceptable, * from private to public. */ ANY, /** * Value that means that any other access modifier other than 'private' * is considered auto-detectable. */ NON_PRIVATE, /** * Value that means access modifiers 'protected' and 'public' are * auto-detectable (and 'private' and "package access" == no modifiers * are not) */ PROTECTED_AND_PUBLIC, /** * Value to indicate that only 'public' access modifier is considered * auto-detectable. */ PUBLIC_ONLY, /** * Value that indicates that no access modifiers are auto-detectable: * this can be used to explicitly disable auto-detection for specified * types. */ NONE, /** * Value that indicates that default visibility level (whatever it is, * depends on context) is to be used. This usually means that inherited * value (from parent visibility settings) is to be used. */ DEFAULT; public boolean isVisible(Member m) { switch (this) { case ANY: return true; case NONE: return false; case NON_PRIVATE: return !Modifier.isPrivate(m.getModifiers()); case PROTECTED_AND_PUBLIC: if (Modifier.isProtected(m.getModifiers())) { return true; } // fall through to public case: case PUBLIC_ONLY: return Modifier.isPublic(m.getModifiers()); } return false; } } /** * Types of property elements (getters, setters, fields, creators) that * can be auto-detected. * NOTE: as of 1.5, it is recommended that instead of defining this property, * distinct visibility properties are used instead. This because levels * used with this method are not explicit, but global defaults that differ for different * methods. As such, this property can be considered deprecated and * only retained for backwards compatibility. */ JsonMethod[] value() default { JsonMethod.ALL }; /** * Minimum visibility required for auto-detecting regular getter methods. * * @since 1.5 */ Visibility getterVisibility() default Visibility.DEFAULT; /** * Minimum visibility required for auto-detecting is-getter methods. * * @since 1.5 */ Visibility isGetterVisibility() default Visibility.DEFAULT; /** * Minimum visibility required for auto-detecting setter methods. * * @since 1.5 */ Visibility setterVisibility() default Visibility.DEFAULT; /** * Minimum visibility required for auto-detecting Creator methods, * except for no-argument constructors (which are always detected * no matter what). * * @since 1.5 */ Visibility creatorVisibility() default Visibility.DEFAULT; /** * Minimum visibility required for auto-detecting member fields. * * @since 1.5 */ Visibility fieldVisibility() default Visibility.DEFAULT; } jackson-src-1.9.2/src/java/org/codehaus/jackson/annotate/JsonManagedReference.java0000644000175000017500000000337311655120726030630 0ustar jamespagejamespagepackage org.codehaus.jackson.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation used to indicate that annotated property is part of * two-way linkage between fields; and that its role is "parent" (or "forward") link. * Value type (class) of property must have a single compatible property annotated with * {@link JsonBackReference}. Linkage is handled such that the property * annotated with this annotation is handled normally (serialized normally, no * special handling for deserialization); it is the matching back reference * that requires special handling *

* All references have logical name to allow handling multiple linkages; typical case * would be that where nodes have both parent/child and sibling linkages. If so, * pairs of references should be named differently. * It is an error for a class too have multiple managed references with same name, * even if types pointed are different. *

* Note: only methods and fields can be annotated with this annotation: constructor * arguments should NOT be annotated, as they can not be either managed or back * references. * * @author tatu */ @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonManagedReference { /** * Logical have for the reference property pair; used to link managed and * back references. Default name can be used if there is just single * reference pair (for example, node class that just has parent/child linkage, * consisting of one managed reference and matching back reference) */ public String value() default "defaultReference"; } jackson-src-1.9.2/src/java/org/codehaus/jackson/type/0000755000175000017500000000000011672662540023126 5ustar jamespagejamespagejackson-src-1.9.2/src/java/org/codehaus/jackson/type/package-info.java0000644000175000017500000000062211655120726026311 0ustar jamespagejamespage/** * Contains classes needed for type introspection, mostly used by data binding * functionality. Most of this functionality is needed to properly handled * generic types, and to simplify and unify processing of things Jackson needs * to determine how contained types (of {@link java.util.Collection} and * {@link java.util.Map} classes) are to be handled. */ package org.codehaus.jackson.type; jackson-src-1.9.2/src/java/org/codehaus/jackson/type/JavaType.java0000644000175000017500000003724711655120726025525 0ustar jamespagejamespagepackage org.codehaus.jackson.type; import java.lang.reflect.Modifier; /** * Base class for type token classes used both to contain information * and as keys for deserializers. *

* Instances can (only) be constructed by * {@link org.codehaus.jackson.map.type.TypeFactory}. */ public abstract class JavaType { /** * This is the nominal type-erased Class that would be close to the * type represented (but not exactly type, due to type erasure: type * instance may have more information on this). * May be an interface or abstract class, so instantiation * may not be possible. */ protected final Class _class; protected final int _hashCode; /** * Optional handler (codec) that can be attached to indicate * what to use for handling (serializing, deserializing) values of * this specific type. *

* Note: untyped (i.e. caller has to cast) because it is used for * different kinds of handlers, with unrelated types. *

* TODO: make final and possible promote to sub-classes * * @since 1.3 */ protected /*final*/ Object _valueHandler; /** * Optional handler that can be attached to indicate how to handle * additional type metadata associated with this type. *

* Note: untyped (i.e. caller has to cast) because it is used for * different kinds of handlers, with unrelated types. *

* TODO: make final and possible promote to sub-classes * * @since 1.5 */ protected /*final*/ Object _typeHandler; /* /********************************************************** /* Life-cycle /********************************************************** */ /** * @param raw "Raw" (type-erased) class for this type * @param additionalHash Additional hash code to use, in addition * to hash code of the class name */ protected JavaType(Class raw, int additionalHash) { _class = raw; _hashCode = raw.getName().hashCode() + additionalHash; _valueHandler = null; _typeHandler = null; } /** * "Copy method" that will construct a new instance that is identical to * this instance, except that it will have specified type handler assigned. * * @return Newly created type instance * * @since 1.7 */ public abstract JavaType withTypeHandler(Object h); /** * "Copy method" that will construct a new instance that is identical to * this instance, except that its content type will have specified * type handler assigned. * * @return Newly created type instance * * @since 1.7 */ public abstract JavaType withContentTypeHandler(Object h); // !!! TODO: in 2.0, change to be abstract method //public abstract JavaType withValueHandler(Object h); /** * @since 1.9 */ public JavaType withValueHandler(Object h) { /* 16-Aug-2011, tatu: This is not entirely correct, as we can not * create new immutable instances. However, sub-classes can, * so if mapper is version 1.9, things work as expected. * Otherwise, in 2.0 we can make this method abstract. */ setValueHandler(h); return this; } // !!! TODO: in 2.0, change to be abstract method //public abstract JavaType withContentValueHandler(Object h); /** * @since 1.9 */ public JavaType withContentValueHandler(Object h) { /* 16-Aug-2011, tatu: This is not entirely correct, as we can not * create new immutable instances. However, sub-classes can, * so if mapper is version 1.9, things work as expected. * Otherwise, in 2.0 we can make this method abstract. */ getContentType().setValueHandler(h); return this; } /** * Method for assigning handler to associate with this type; or * if null passed, to remove such assignment * * @since 1.3 * * @deprecated Since 1.9, should not be used; instead, use * withContentTypeHandler and * withContentValueHandler methods. */ @Deprecated public void setValueHandler(Object h) { // sanity check, should be assigned just once if (h != null && _valueHandler != null) { throw new IllegalStateException("Trying to reset value handler for type ["+toString() +"]; old handler of type "+_valueHandler.getClass().getName()+", new handler of type "+h.getClass().getName()); } _valueHandler = h; } /* /********************************************************** /* Type coercion fluent factory methods /********************************************************** */ /** * Method that can be called to do a "narrowing" conversions; that is, * to return a type with a raw class that is assignable to the raw * class of this type. If this is not possible, an * {@link IllegalArgumentException} is thrown. * If class is same as the current raw class, instance itself is * returned. */ public JavaType narrowBy(Class subclass) { // First: if same raw class, just return this instance if (subclass == _class) { return this; } // Otherwise, ensure compatibility _assertSubclass(subclass, _class); JavaType result = _narrow(subclass); // TODO: these checks should NOT actually be needed; above should suffice: if (_valueHandler != result.getValueHandler()) { result = result.withValueHandler(_valueHandler); } if (_typeHandler != result.getTypeHandler()) { result = result.withTypeHandler(_typeHandler); } return result; } /** * More efficient version of {@link #narrowBy}, called by * internal framework in cases where compatibility checks * are to be skipped. * * @since 1.5 */ public JavaType forcedNarrowBy(Class subclass) { if (subclass == _class) { // can still optimize for simple case return this; } JavaType result = _narrow(subclass); // TODO: these checks should NOT actually be needed; above should suffice: if (_valueHandler != result.getValueHandler()) { result = result.withValueHandler(_valueHandler); } if (_typeHandler != result.getTypeHandler()) { result = result.withTypeHandler(_typeHandler); } return result; } /** * Method that can be called to do a "widening" conversions; that is, * to return a type with a raw class that could be assigned from this * type. * If such conversion is not possible, an * {@link IllegalArgumentException} is thrown. * If class is same as the current raw class, instance itself is * returned. */ public JavaType widenBy(Class superclass) { // First: if same raw class, just return this instance if (superclass == _class) { return this; } // Otherwise, ensure compatibility _assertSubclass(_class, superclass); return _widen(superclass); } protected abstract JavaType _narrow(Class subclass); /** *

* Default implementation is just to call {@link #_narrow}, since * underlying type construction is usually identical */ protected JavaType _widen(Class superclass) { return _narrow(superclass); } public abstract JavaType narrowContentsBy(Class contentClass); /** * @since 1.8 */ public abstract JavaType widenContentsBy(Class contentClass); /* /********************************************************** /* Public API, simple accessors /********************************************************** */ public final Class getRawClass() { return _class; } /** * Method that can be used to check whether this type has * specified Class as its type erasure. Put another way, returns * true if instantiation of this Type is given (type-erased) Class. */ public final boolean hasRawClass(Class clz) { return _class == clz; } public boolean isAbstract() { return Modifier.isAbstract(_class.getModifiers()); } /** * @since 1.3 */ public boolean isConcrete() { int mod = _class.getModifiers(); if ((mod & (Modifier.INTERFACE | Modifier.ABSTRACT)) == 0) { return true; } /* 19-Feb-2010, tatus: Holy mackarel; primitive types * have 'abstract' flag set... */ if (_class.isPrimitive()) { return true; } return false; } public boolean isThrowable() { return Throwable.class.isAssignableFrom(_class); } public boolean isArrayType() { return false; } public final boolean isEnumType() { return _class.isEnum(); } public final boolean isInterface() { return _class.isInterface(); } public final boolean isPrimitive() { return _class.isPrimitive(); } public final boolean isFinal() { return Modifier.isFinal(_class.getModifiers()); } /** * @return True if type represented is a container type; this includes * array, Map and Collection types. */ public abstract boolean isContainerType(); /** * @return True if type is either true {@link java.util.Collection} type, * or something similar (meaning it has at least one type parameter, * which describes type of contents) * * @since 1.8 */ public boolean isCollectionLikeType() { return false; } /** * @return True if type is either true {@link java.util.Map} type, * or something similar (meaning it has at least two type parameter; * first one describing key type, second value type) * * @since 1.8 */ public boolean isMapLikeType() { return false; } /* /********************************************************** /* Public API, type parameter access /********************************************************** */ /** * Method that can be used to find out if the type directly declares generic * parameters (for its direct super-class and/or super-interfaces). * * @since 1.6 */ public boolean hasGenericTypes() { return containedTypeCount() > 0; } /** * Method for accessing key type for this type, assuming type * has such a concept (only Map types do) */ public JavaType getKeyType() { return null; } /** * Method for accessing content type of this type, if type has * such a thing: simple types do not, structured types do * (like arrays, Collections and Maps) */ public JavaType getContentType() { return null; } /** * Method for checking how many contained types this type * has. Contained types are usually generic types, so that * generic Maps have 2 contained types. * * @since 1.5 */ public int containedTypeCount() { return 0; } /** * Method for accessing definitions of contained ("child") * types. * * @param index Index of contained type to return * * @return Contained type at index, or null if no such type * exists (no exception thrown) * * @since 1.5 */ public JavaType containedType(int index) { return null; } /** * Method for accessing name of type variable in indicated * position. If no name is bound, will use placeholders (derived * from 0-based index); if no type variable or argument exists * with given index, null is returned. * * @param index Index of contained type to return * * @return Contained type at index, or null if no such type * exists (no exception thrown) * * @since 1.5 */ public String containedTypeName(int index) { return null; } /* /********************************************************** /* Semi-public API, accessing handlers /********************************************************** */ /** * Method for accessing value handler associated with this type, if any * * @since 1.3 */ @SuppressWarnings("unchecked") public T getValueHandler() { return (T) _valueHandler; } /** * Method for accessing type handler associated with this type, if any * * @since 1.5 */ @SuppressWarnings("unchecked") public T getTypeHandler() { return (T) _typeHandler; } /* /********************************************************** /* Support for producing signatures (1.6+) /********************************************************** */ /** * Method that can be used to serialize type into form from which * it can be fully deserialized from at a later point (using * TypeFactory from mapper package). * For simple types this is same as calling * {@link Class#getName}, but for structured types it may additionally * contain type information about contents. * * @since 1.5 */ public abstract String toCanonical(); /** * Method for accessing signature that contains generic * type information, in form compatible with JVM 1.5 * as per JLS. It is a superset of {@link #getErasedSignature}, * in that generic information can be automatically removed * if necessary (just remove outermost * angle brackets along with content inside) * * @since 1.6 */ public String getGenericSignature() { StringBuilder sb = new StringBuilder(40); getGenericSignature(sb); return sb.toString(); } /** * * @param sb StringBuilder to append signature to * * @return StringBuilder that was passed in; returned to allow * call chaining * * @since 1.6 */ public abstract StringBuilder getGenericSignature(StringBuilder sb); /** * Method for accessing signature without generic * type information, in form compatible with all versions * of JVM, and specifically used for type descriptions * when generating byte code. * * @since 1.6 */ public String getErasedSignature() { StringBuilder sb = new StringBuilder(40); getErasedSignature(sb); return sb.toString(); } /** * Method for accessing signature without generic * type information, in form compatible with all versions * of JVM, and specifically used for type descriptions * when generating byte code. * * @param sb StringBuilder to append signature to * * @return StringBuilder that was passed in; returned to allow * call chaining * * @since 1.6 */ public abstract StringBuilder getErasedSignature(StringBuilder sb); /* /********************************************************** /* Helper methods /********************************************************** */ protected void _assertSubclass(Class subclass, Class superClass) { if (!_class.isAssignableFrom(subclass)) { throw new IllegalArgumentException("Class "+subclass.getName()+" is not assignable to "+_class.getName()); } } /* /********************************************************** /* Standard methods; let's make them abstract to force override /********************************************************** */ @Override public abstract String toString(); @Override public abstract boolean equals(Object o); @Override public final int hashCode() { return _hashCode; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/type/TypeReference.java0000644000175000017500000000436111655120726026531 0ustar jamespagejamespagepackage org.codehaus.jackson.type; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * This class is used to pass full generics type information, and * avoid problems with type erasure (that basically removes most * usable type references from runtime Class objects). * It is based on ideas from * http://gafter.blogspot.com/2006/12/super-type-tokens.html, * Additional idea (from a suggestion made in comments of the article) * is to require bogus implementation of Comparable * (any such generic interface would do, as long as it forces a method * with generic type to be implemented). * to ensure that a Type argument is indeed given. *

* Usage is by sub-classing: here is one way to instantiate reference * to generic type List<Integer>: *

 *  TypeReference ref = new TypeReference<List<Integer>>() { };
 *
* which can be passed to methods that accept TypeReference. */ public abstract class TypeReference implements Comparable> { final Type _type; protected TypeReference() { Type superClass = getClass().getGenericSuperclass(); if (superClass instanceof Class) { // sanity check, should never happen throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information"); } /* 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect * it is possible to make it fail? * But let's deal with specifc * case when we know an actual use case, and thereby suitable * work arounds for valid case(s) and/or error to throw * on invalid one(s). */ _type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; } public Type getType() { return _type; } /** * The only reason we define this method (and require implementation * of Comparable) is to prevent constructing a * reference without type information. */ @Override public int compareTo(TypeReference o) { // just need an implementation, not a good one... hence: return 0; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonLocation.java0000644000175000017500000001027311655120726025411 0ustar jamespagejamespagepackage org.codehaus.jackson; import org.codehaus.jackson.annotate.JsonCreator; import org.codehaus.jackson.annotate.JsonProperty; /** * Object that encapsulates Location information used for reporting * parsing (or potentially generation) errors, as well as current location * within input streams. */ public class JsonLocation implements java.io.Serializable // as per [JACKSON-168] { private static final long serialVersionUID = 1L; /** * Shared immutable "N/A location" that can be returned to indicate * that no location information is available * * @since 1.3 */ public final static JsonLocation NA = new JsonLocation("N/A", -1L, -1L, -1, -1); final long _totalBytes; final long _totalChars; final int _lineNr; final int _columnNr; /** * Displayable description for input source: file path, url */ final Object _sourceRef; public JsonLocation(Object srcRef, long totalChars, int lineNr, int colNr) { /* Unfortunately, none of legal encodings are straight single-byte * encodings. Could determine offset for UTF-16/UTF-32, but the * most important one is UTF-8... * so for now, we'll just not report any real byte count */ this(srcRef, -1L, totalChars, lineNr, colNr); } @JsonCreator public JsonLocation(@JsonProperty("sourceRef") Object sourceRef, @JsonProperty("byteOffset") long totalBytes, @JsonProperty("charOffset") long totalChars, @JsonProperty("lineNr") int lineNr, @JsonProperty("columnNr") int columnNr) { _sourceRef = sourceRef; _totalBytes = totalBytes; _totalChars = totalChars; _lineNr = lineNr; _columnNr = columnNr; } /** * Reference to the original resource being read, if one available. * For example, when a parser has been constructed by passing * a {@link java.io.File} instance, this method would return * that File. Will return null if no such reference is available, * for example when {@link java.io.InputStream} was used to * construct the parser instance. */ public Object getSourceRef() { return _sourceRef; } /** * @return Line number of the location (1-based) */ public int getLineNr() { return _lineNr; } /** * @return Column number of the location (1-based) */ public int getColumnNr() { return _columnNr; } /** * @return Character offset within underlying stream, reader or writer, * if available; -1 if not. */ public long getCharOffset() { return _totalChars; } /** * @return Byte offset within underlying stream, reader or writer, * if available; -1 if not. */ public long getByteOffset() { return _totalBytes; } @Override public String toString() { StringBuilder sb = new StringBuilder(80); sb.append("[Source: "); if (_sourceRef == null) { sb.append("UNKNOWN"); } else { sb.append(_sourceRef.toString()); } sb.append("; line: "); sb.append(_lineNr); sb.append(", column: "); sb.append(_columnNr); sb.append(']'); return sb.toString(); } @Override public int hashCode() { int hash = (_sourceRef == null) ? 1 : _sourceRef.hashCode(); hash ^= _lineNr; hash += _columnNr; hash ^= (int) _totalChars; hash += (int) _totalBytes; return hash; } @Override public boolean equals(Object other) { if (other == this) return true; if (other == null) return false; if (!(other instanceof JsonLocation)) return false; JsonLocation otherLoc = (JsonLocation) other; if (_sourceRef == null) { if (otherLoc._sourceRef != null) return false; } else if (!_sourceRef.equals(otherLoc._sourceRef)) return false; return (_lineNr == otherLoc._lineNr) && (_columnNr == otherLoc._columnNr) && (_totalChars == otherLoc._totalChars) && (getByteOffset() == otherLoc.getByteOffset()) ; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/ObjectCodec.java0000644000175000017500000001222011655120726025145 0ustar jamespagejamespagepackage org.codehaus.jackson; import java.io.IOException; import java.util.Iterator; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.TypeReference; /** * Abstract class that defines the interface that {@link JsonParser} and * {@link JsonGenerator} use to serialize and deserialize regular * Java objects (POJOs aka Beans). *

* The standard implementation of this class is * {@link org.codehaus.jackson.map.ObjectMapper}. */ public abstract class ObjectCodec { protected ObjectCodec() { } /* /********************************************************** /* API for de-serialization (JSON-to-Object) /********************************************************** */ /** * Method to deserialize JSON content into a non-container * type (it can be an array type, however): typically a bean, array * or a wrapper type (like {@link java.lang.Boolean}). *

* Note: this method should NOT be used if the result type is a * container ({@link java.util.Collection} or {@link java.util.Map}. * The reason is that due to type erasure, key and value types * can not be introspected when using this method. */ public abstract T readValue(JsonParser jp, Class valueType) throws IOException, JsonProcessingException; /** * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using so-called * "super type token" * and specifically needs to be used if the root type is a * parameterized (generic) container type. */ public abstract T readValue(JsonParser jp, TypeReference valueTypeRef) throws IOException, JsonProcessingException; /** * Method to deserialize JSON content as tree expressed * using set of {@link JsonNode} instances. Returns * root of the resulting tree (where root can consist * of just a single node if the current event is a * value event, not container). */ public abstract T readValue(JsonParser jp, JavaType valueType) throws IOException, JsonProcessingException; /** * Method to deserialize JSON content as tree expressed * using set of {@link JsonNode} instances. Returns * root of the resulting tree (where root can consist * of just a single node if the current event is a * value event, not container). */ public abstract JsonNode readTree(JsonParser jp) throws IOException, JsonProcessingException; /** * Method for reading sequence of Objects from parser stream, * all with same specified value type. * * @since 1.9 */ public abstract Iterator readValues(JsonParser jp, Class valueType) throws IOException, JsonProcessingException; /** * Method for reading sequence of Objects from parser stream, * all with same specified value type. * * @since 1.9 */ public abstract Iterator readValues(JsonParser jp, TypeReference valueTypeRef) throws IOException, JsonProcessingException; /** * Method for reading sequence of Objects from parser stream, * all with same specified value type. * * @since 1.9 */ public abstract Iterator readValues(JsonParser jp, JavaType valueType) throws IOException, JsonProcessingException; /* /********************************************************** /* API for serialization (Object-to-JSON) /********************************************************** */ /** * Method to serialize given Java Object, using generator * provided. */ public abstract void writeValue(JsonGenerator jgen, Object value) throws IOException, JsonProcessingException; /** * Method to serialize given Json Tree, using generator * provided. */ public abstract void writeTree(JsonGenerator jgen, JsonNode rootNode) throws IOException, JsonProcessingException; /* /********************************************************** /* API for Tree Model handling /********************************************************** */ /** * Method for construct root level Object nodes * for Tree Model instances. * * @since 1.2 */ public abstract JsonNode createObjectNode(); /** * Method for construct root level Array nodes * for Tree Model instances. * * @since 1.2 */ public abstract JsonNode createArrayNode(); /** * Method for constructing a {@link JsonParser} for reading * contents of a JSON tree, as if it was external serialized * JSON content. * * @since 1.3 */ public abstract JsonParser treeAsTokens(JsonNode n); /** * Convenience method for converting given JSON tree into instance of specified * value type. This is equivalent to first constructing a {@link JsonParser} to * iterate over contents of the tree, and using that parser for data binding. * * @since 1.3 */ public abstract T treeToValue(JsonNode n, Class valueType) throws IOException, JsonProcessingException; } jackson-src-1.9.2/src/java/org/codehaus/jackson/FormatSchema.java0000644000175000017500000000241011655120726025352 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Simple tag interface used to mark schema objects that are used by some * {@link JsonParser} and {@link JsonGenerator} implementations to further * specify structure of expected format. * Basic JSON-based parsers and generators do not use schemas, but some data * formats (like many binary data formats like Thrift, protobuf) mandate * use of schemas. *

* Since there is little commonality between schemas for different data formats, * this interface does not define much meaningful functionality for accessing * schema details; rather, specific parser and generator implementations need * to cast to schema implementations they use. This marker interface is mostly * used for tagging "some kind of schema" -- instead of passing opaque * {@link java.lang.Object} -- for documentation purposes. * * @since 1.8 */ public interface FormatSchema { /** * Method that can be used to get an identifier that can be used for diagnostics * purposes, to indicate what kind of data format this schema is used for: typically * it is a short name of format itself, but it can also contain additional information * in cases where data format supports multiple types of schemas. */ public String getSchemaType(); } jackson-src-1.9.2/src/java/org/codehaus/jackson/JsonGenerator.java0000644000175000017500000012501111655120726025564 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.io.CharacterEscapes; import org.codehaus.jackson.io.SerializedString; /** * Base class that defines public API for writing JSON content. * Instances are created using factory methods of * a {@link JsonFactory} instance. * * @author Tatu Saloranta */ public abstract class JsonGenerator implements Closeable, Versioned { /** * Enumeration that defines all togglable features for generators. */ public enum Feature { /** * Feature that determines whether generator will automatically * close underlying output target that is NOT owned by the * generator. * If disabled, calling application has to separately * close the underlying {@link OutputStream} and {@link Writer} * instances used to create the generator. If enabled, generator * will handle closing, as long as generator itself gets closed: * this happens when end-of-input is encountered, or generator * is closed by a call to {@link JsonGenerator#close}. *

* Feature is enabled by default. */ AUTO_CLOSE_TARGET(true), /** * Feature that determines what happens when the generator is * closed while there are still unmatched * {@link JsonToken#START_ARRAY} or {@link JsonToken#START_OBJECT} * entries in output content. If enabled, such Array(s) and/or * Object(s) are automatically closed; if disabled, nothing * specific is done. *

* Feature is enabled by default. */ AUTO_CLOSE_JSON_CONTENT(true), /** * Feature that determines whether JSON Object field names are * quoted using double-quotes, as specified by JSON specification * or not. Ability to disable quoting was added to support use * cases where they are not usually expected, which most commonly * occurs when used straight from Javascript. */ QUOTE_FIELD_NAMES(true), /** * Feature that determines whether "exceptional" (not real number) * float/double values are output as quoted strings. * The values checked are Double.Nan, * Double.POSITIVE_INFINITY and Double.NEGATIVE_INIFINTY (and * associated Float values). * If feature is disabled, these numbers are still output using * associated literal values, resulting in non-conformant * output. *

* Feature is enabled by default. */ QUOTE_NON_NUMERIC_NUMBERS(true), /** * Feature that forces all Java numbers to be written as JSON strings. * Default state is 'false', meaning that Java numbers are to * be serialized using basic numeric serialization (as JSON * numbers, integral or floating point). If enabled, all such * numeric values are instead written out as JSON Strings. *

* One use case is to avoid problems with Javascript limitations: * since Javascript standard specifies that all number handling * should be done using 64-bit IEEE 754 floating point values, * result being that some 64-bit integer values can not be * accurately represent (as mantissa is only 51 bit wide). *

* Feature is disabled by default. * * @since 1.3 */ WRITE_NUMBERS_AS_STRINGS(false), /** * Feature that specifies that calls to {@link #flush} will cause * matching flush() to underlying {@link OutputStream} * or {@link Writer}; if disabled this will not be done. * Main reason to disable this feature is to prevent flushing at * generator level, if it is not possible to prevent method being * called by other code (like ObjectMapper or third * party libraries). *

* Feature is enabled by default. * * @since 1.7 */ FLUSH_PASSED_TO_STREAM(true), /** * Feature that specifies that all characters beyond 7-bit ASCII * range (i.e. code points of 128 and above) need to be output * using format-specific escapes (for JSON, backslash escapes), * if format uses escaping mechanisms (which is generally true * for textual formats but not for binary formats). * * @since 1.8 */ ESCAPE_NON_ASCII(false) ; final boolean _defaultState; final int _mask; /** * Method that calculates bit set (flags) of all features that * are enabled by default. */ public static int collectDefaults() { int flags = 0; for (Feature f : values()) { if (f.enabledByDefault()) { flags |= f.getMask(); } } return flags; } private Feature(boolean defaultState) { _defaultState = defaultState; _mask = (1 << ordinal()); } public boolean enabledByDefault() { return _defaultState; } public int getMask() { return _mask; } } /* /********************************************************** /* Configuration /********************************************************** */ /** * Object that handles pretty-printing (usually additional * white space to make results more human-readable) during * output. If null, no pretty-printing is done. */ protected PrettyPrinter _cfgPrettyPrinter; /* /********************************************************** /* Construction, configuration, initialization /********************************************************** */ protected JsonGenerator() { } /** * Method to call to make this generator use specified schema. * Method must be called before generating any content, right after instance * has been created. * Note that not all generators support schemas; and those that do usually only * accept specific types of schemas: ones defined for data format this generator * produces. *

* If generator does not support specified schema, {@link UnsupportedOperationException} * is thrown. * * @param schema Schema to use * * @throws UnsupportedOperationException if generator does not support schema * * @since 1.8 */ public void setSchema(FormatSchema schema) { throw new UnsupportedOperationException("Generator of type "+getClass().getName()+" does not support schema of type '" +schema.getSchemaType()+"'"); } /** * Method that can be used to verify that given schema can be used with * this generator (using {@link #setSchema}). * * @param schema Schema to check * * @return True if this generator can use given schema; false if not * * @since 1.8 */ public boolean canUseSchema(FormatSchema schema) { return false; } /** * @since 1.6 */ @Override public Version version() { return Version.unknownVersion(); } /** * Method that can be used to get access to object that is used * as target for generated output; this is usually either * {@link OutputStream} or {@link Writer}, depending on what * generator was constructed with. * Note that returned value may be null in some cases; including * case where implementation does not want to exposed raw * source to caller. * In cases where output has been decorated, object returned here * is the decorated version; this allows some level of interaction * between users of generator and decorator object. *

* In general use of this accessor should be considered as * "last effort", i.e. only used if no other mechanism is applicable. * * @since 1.8 */ public Object getOutputTarget() { return null; } /* /********************************************************** /* Public API, configuration /********************************************************** */ /** * Method for enabling specified parser features: * check {@link Feature} for list of available features. * * @return Generator itself (this), to allow chaining * * @since 1.2 */ public abstract JsonGenerator enable(Feature f); /** * Method for disabling specified features * (check {@link Feature} for list of features) * * @return Generator itself (this), to allow chaining * * @since 1.2 */ public abstract JsonGenerator disable(Feature f); /** * Method for enabling or disabling specified feature: * check {@link Feature} for list of available features. * * @return Generator itself (this), to allow chaining * * @since 1.2 */ public JsonGenerator configure(Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; } /** * Method for checking whether given feature is enabled. * Check {@link Feature} for list of available features. * * @since 1.2 */ public abstract boolean isEnabled(Feature f); /** * Method that can be called to set or reset the object to * use for writing Java objects as JsonContent * (using method {@link #writeObject}). * * @return Generator itself (this), to allow chaining */ public abstract JsonGenerator setCodec(ObjectCodec oc); /** * Method for accessing the object used for writing Java * object as Json content * (using method {@link #writeObject}). */ public abstract ObjectCodec getCodec(); // // // Older deprecated versions /** @deprecated Use {@link #enable} instead */ @Deprecated public void enableFeature(Feature f) { enable(f); } /** @deprecated Use {@link #disable} instead */ @Deprecated public void disableFeature(Feature f) { disable(f); } /** @deprecated Use {@link #configure} instead */ @Deprecated public void setFeature(Feature f, boolean state) { configure(f, state); } /** @deprecated Use {@link #isEnabled} instead */ @Deprecated public boolean isFeatureEnabled(Feature f) { return isEnabled(f); } /* /********************************************************** /* Configuring generator /********************************************************** */ /** * Method for setting a custom pretty printer, which is usually * used to add indentation for improved human readability. * By default, generator does not do pretty printing. *

* To use the default pretty printer that comes with core * Jackson distribution, call {@link #useDefaultPrettyPrinter} * instead. * * @return Generator itself (this), to allow chaining */ public JsonGenerator setPrettyPrinter(PrettyPrinter pp) { _cfgPrettyPrinter = pp; return this; } /** * Convenience method for enabling pretty-printing using * the default pretty printer * ({@link org.codehaus.jackson.util.DefaultPrettyPrinter}). * * @return Generator itself (this), to allow chaining */ public abstract JsonGenerator useDefaultPrettyPrinter(); /** * Method that can be called to request that generator escapes * all character codes above specified code point (if positive value); * or, to not escape any characters except for ones that must be * escaped for the data format (if -1). * To force escaping of all non-ASCII characters, for example, * this method would be called with value of 127. *

* Note that generators are NOT required to support setting of value * higher than 127, because there are other ways to affect quoting * (or lack thereof) of character codes between 0 and 127. * Not all generators support concept of escaping, either; if so, * calling this method will have no effect. *

* Default implementation does nothing; sub-classes need to redefine * it according to rules of supported data format. * * @param charCode Either -1 to indicate that no additional escaping * is to be done; or highest code point not to escape (meaning higher * ones will be), if positive value. * * @since 1.8 */ public JsonGenerator setHighestNonEscapedChar(int charCode) { return this; } /** * Accessor method for testing what is the highest unescaped character * configured for this generator. This may be either positive value * (when escaping configuration has been set and is in effect), or * 0 to indicate that no additional escaping is in effect. * Some generators may not support additional escaping: for example, * generators for binary formats that do not use escaping should * simply return 0. * * @return Currently active limitation for highest non-escaped character, * if defined; or -1 to indicate no additional escaping is performed. */ public int getHighestEscapedChar() { return 0; } /** * Method for accessing custom escapes factory uses for {@link JsonGenerator}s * it creates. * * @since 1.8 */ public CharacterEscapes getCharacterEscapes() { return null; } /** * Method for defining custom escapes factory uses for {@link JsonGenerator}s * it creates. * * @since 1.8 */ public JsonGenerator setCharacterEscapes(CharacterEscapes esc) { return this; } /* /********************************************************** /* Public API, write methods, structural /********************************************************** */ /** * Method for writing starting marker of a JSON Array value * (character '['; plus possible white space decoration * if pretty-printing is enabled). *

* Array values can be written in any context where values * are allowed: meaning everywhere except for when * a field name is expected. */ public abstract void writeStartArray() throws IOException, JsonGenerationException; /** * Method for writing closing marker of a JSON Array value * (character ']'; plus possible white space decoration * if pretty-printing is enabled). *

* Marker can be written if the innermost structured type * is Array. */ public abstract void writeEndArray() throws IOException, JsonGenerationException; /** * Method for writing starting marker of a JSON Object value * (character '{'; plus possible white space decoration * if pretty-printing is enabled). *

* Object values can be written in any context where values * are allowed: meaning everywhere except for when * a field name is expected. */ public abstract void writeStartObject() throws IOException, JsonGenerationException; /** * Method for writing closing marker of a JSON Object value * (character '}'; plus possible white space decoration * if pretty-printing is enabled). *

* Marker can be written if the innermost structured type * is Object, and the last written event was either a * complete value, or START-OBJECT marker (see JSON specification * for more details). */ public abstract void writeEndObject() throws IOException, JsonGenerationException; /** * Method for writing a field name (JSON String surrounded by * double quotes: syntactically identical to a JSON String value), * possibly decorated by white space if pretty-printing is enabled. *

* Field names can only be written in Object context (check out * JSON specification for details), when field name is expected * (field names alternate with values). */ public abstract void writeFieldName(String name) throws IOException, JsonGenerationException; /** * Method similar to {@link #writeFieldName(String)}, main difference * being that it may perform better as some of processing (such as * quoting of certain characters, or encoding into external encoding * if supported by generator) can be done just once and reused for * later calls. *

* Default implementation simple uses unprocessed name container in * serialized String; implementations are strongly encouraged to make * use of more efficient methods argument object has. * * @since 1.6 */ public void writeFieldName(SerializedString name) throws IOException, JsonGenerationException { writeFieldName(name.getValue()); } /** * Method similar to {@link #writeFieldName(String)}, main difference * being that it may perform better as some of processing (such as * quoting of certain characters, or encoding into external encoding * if supported by generator) can be done just once and reused for * later calls. *

* Default implementation simple uses unprocessed name container in * serialized String; implementations are strongly encouraged to make * use of more efficient methods argument object has. * * @since 1.7 */ public void writeFieldName(SerializableString name) throws IOException, JsonGenerationException { writeFieldName(name.getValue()); } /* /********************************************************** /* Public API, write methods, text/String values /********************************************************** */ /** * Method for outputting a String value. Depending on context * this means either array element, (object) field value or * a stand alone String; but in all cases, String will be * surrounded in double quotes, and contents will be properly * escaped as required by JSON specification. */ public abstract void writeString(String text) throws IOException, JsonGenerationException; /** * Method for outputting a String value. Depending on context * this means either array element, (object) field value or * a stand alone String; but in all cases, String will be * surrounded in double quotes, and contents will be properly * escaped as required by JSON specification. */ public abstract void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException; /** * Method similar to {@link #writeString(String)}, but that takes * {@link SerializableString} which can make this potentially * more efficient to call as generator may be able to reuse * quoted and/or encoded representation. *

* Default implementation just calls {@link #writeString(String)}; * sub-classes should override it with more efficient implementation * if possible. * * @since 1.7 */ public void writeString(SerializableString text) throws IOException, JsonGenerationException { writeString(text.getValue()); } /** * Method similar to {@link #writeString(String)} but that takes as * its input a UTF-8 encoded String that is to be output as-is, without additional * escaping (type of which depends on data format; backslashes for JSON). * However, quoting that data format requires (like double-quotes for JSON) will be added * around the value if and as necessary. *

* Note that some backends may choose not to support this method: for * example, if underlying destination is a {@link java.io.Writer} * using this method would require UTF-8 decoding. * If so, implementation may instead choose to throw a * {@link UnsupportedOperationException} due to ineffectiveness * of having to decode input. * * @since 1.7 */ public abstract void writeRawUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException; /** * Method similar to {@link #writeString(String)} but that takes as its input * a UTF-8 encoded String which has not been escaped using whatever * escaping scheme data format requires (for JSON that is backslash-escaping * for control characters and double-quotes; for other formats something else). * This means that textual JSON backends need to check if value needs * JSON escaping, but otherwise can just be copied as is to output. * Also, quoting that data format requires (like double-quotes for JSON) will be added * around the value if and as necessary. *

* Note that some backends may choose not to support this method: for * example, if underlying destination is a {@link java.io.Writer} * using this method would require UTF-8 decoding. * In this case * generator implementation may instead choose to throw a * {@link UnsupportedOperationException} due to ineffectiveness * of having to decode input. * * @since 1.7 */ public abstract void writeUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException; /* /********************************************************** /* Public API, write methods, binary/raw content /********************************************************** */ /** * Method that will force generator to copy * input text verbatim with no modifications (including * that no escaping is done and no separators are added even * if context [array, object] would otherwise require such). * If such separators are desired, use * {@link #writeRawValue(String)} instead. *

* Note that not all generator implementations necessarily support * such by-pass methods: those that do not will throw * {@link UnsupportedOperationException}. */ public abstract void writeRaw(String text) throws IOException, JsonGenerationException; /** * Method that will force generator to copy * input text verbatim with no modifications (including * that no escaping is done and no separators are added even * if context [array, object] would otherwise require such). * If such separators are desired, use * {@link #writeRawValue(String)} instead. *

* Note that not all generator implementations necessarily support * such by-pass methods: those that do not will throw * {@link UnsupportedOperationException}. */ public abstract void writeRaw(String text, int offset, int len) throws IOException, JsonGenerationException; /** * Method that will force generator to copy * input text verbatim with no modifications (including * that no escaping is done and no separators are added even * if context [array, object] would otherwise require such). * If such separators are desired, use * {@link #writeRawValue(String)} instead. *

* Note that not all generator implementations necessarily support * such by-pass methods: those that do not will throw * {@link UnsupportedOperationException}. */ public abstract void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException; /** * Method that will force generator to copy * input text verbatim with no modifications (including * that no escaping is done and no separators are added even * if context [array, object] would otherwise require such). * If such separators are desired, use * {@link #writeRawValue(String)} instead. *

* Note that not all generator implementations necessarily support * such by-pass methods: those that do not will throw * {@link UnsupportedOperationException}. */ public abstract void writeRaw(char c) throws IOException, JsonGenerationException; /** * Method that will force generator to copy * input text verbatim without any modifications, but assuming * it must constitute a single legal JSON value (number, string, * boolean, null, Array or List). Assuming this, proper separators * are added if and as needed (comma or colon), and generator * state updated to reflect this. */ public abstract void writeRawValue(String text) throws IOException, JsonGenerationException; public abstract void writeRawValue(String text, int offset, int len) throws IOException, JsonGenerationException; public abstract void writeRawValue(char[] text, int offset, int len) throws IOException, JsonGenerationException; /** * Method that will output given chunk of binary data as base64 * encoded, as a complete String value (surrounded by double quotes). * This method defaults *

* Note: because Json Strings can not contain unescaped linefeeds, * if linefeeds are included (as per last argument), they must be * escaped. This adds overhead for decoding without improving * readability. * Alternatively if linefeeds are not included, * resulting String value may violate the requirement of base64 * RFC which mandates line-length of 76 characters and use of * linefeeds. However, all {@link JsonParser} implementations * are required to accept such "long line base64"; as do * typical production-level base64 decoders. * * @param b64variant Base64 variant to use: defines details such as * whether padding is used (and if so, using which character); * what is the maximum line length before adding linefeed, * and also the underlying alphabet to use. */ public abstract void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException, JsonGenerationException; /** * Similar to {@link #writeBinary(Base64Variant,byte[],int,int)}, * but default to using the Jackson default Base64 variant * (which is {@link Base64Variants#MIME_NO_LINEFEEDS}). */ public void writeBinary(byte[] data, int offset, int len) throws IOException, JsonGenerationException { writeBinary(Base64Variants.getDefaultVariant(), data, offset, len); } /** * Similar to {@link #writeBinary(Base64Variant,byte[],int,int)}, * but assumes default to using the Jackson default Base64 variant * (which is {@link Base64Variants#MIME_NO_LINEFEEDS}). Also * assumes that whole byte array is to be output. */ public void writeBinary(byte[] data) throws IOException, JsonGenerationException { writeBinary(Base64Variants.getDefaultVariant(), data, 0, data.length); } /* /********************************************************** /* Public API, write methods, other value types /********************************************************** */ /** * Method for outputting given value as Json number. * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeNumber(int v) throws IOException, JsonGenerationException; /** * Method for outputting given value as Json number. * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeNumber(long v) throws IOException, JsonGenerationException; /** * Method for outputting given value as Json number. * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeNumber(BigInteger v) throws IOException, JsonGenerationException; /** * Method for outputting indicate Json numeric value. * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeNumber(double d) throws IOException, JsonGenerationException; /** * Method for outputting indicate Json numeric value. * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeNumber(float f) throws IOException, JsonGenerationException; /** * Method for outputting indicate Json numeric value. * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeNumber(BigDecimal dec) throws IOException, JsonGenerationException; /** * Write method that can be used for custom numeric types that can * not be (easily?) converted to "standard" Java number types. * Because numbers are not surrounded by double quotes, regular * {@link #writeString} method can not be used; nor * {@link #writeRaw} because that does not properly handle * value separators needed in Array or Object contexts. *

* Note: because of lack of type safety, some generator * implementations may not be able to implement this * method. For example, if a binary json format is used, * it may require type information for encoding; similarly * for generator-wrappers around Java objects or Json nodes. * If implementation does not implement this method, * it needs to throw {@link UnsupportedOperationException}. */ public abstract void writeNumber(String encodedValue) throws IOException, JsonGenerationException, UnsupportedOperationException; /** * Method for outputting literal Json boolean value (one of * Strings 'true' and 'false'). * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeBoolean(boolean state) throws IOException, JsonGenerationException; /** * Method for outputting literal Json null value. * Can be called in any context where a value is expected * (Array value, Object field value, root-level value). * Additional white space may be added around the value * if pretty-printing is enabled. */ public abstract void writeNull() throws IOException, JsonGenerationException; /* /********************************************************** /* Public API, write methods, serializing Java objects /********************************************************** */ /** * Method for writing given Java object (POJO) as Json. * Exactly how the object gets written depends on object * in question (ad on codec, its configuration); for most * beans it will result in Json object, but for others Json * array, or String or numeric value (and for nulls, Json * null literal. * NOTE: generator must have its object codec * set to non-null value; for generators created by a mapping * factory this is the case, for others not. */ public abstract void writeObject(Object pojo) throws IOException, JsonProcessingException; /** * Method for writing given JSON tree (expressed as a tree * where given JsonNode is the root) using this generator. * This will generally just call * {@link #writeObject} with given node, but is added * for convenience and to make code more explicit in cases * where it deals specifically with trees. */ public abstract void writeTree(JsonNode rootNode) throws IOException, JsonProcessingException; /* /********************************************************** /* Public API, convenience field write methods /********************************************************** */ /** * Convenience method for outputting a field entry ("member") * that has a String value. Equivalent to: *

     *  writeFieldName(fieldName);
     *  writeString(value);
     *
*

* Note: many performance-sensitive implementations override this method */ public void writeStringField(String fieldName, String value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeString(value); } /** * Convenience method for outputting a field entry ("member") * that has a boolean value. Equivalent to: *

     *  writeFieldName(fieldName);
     *  writeBoolean(value);
     *
*/ public final void writeBooleanField(String fieldName, boolean value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeBoolean(value); } /** * Convenience method for outputting a field entry ("member") * that has JSON literal value null. Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeNull();
     *
*/ public final void writeNullField(String fieldName) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeNull(); } /** * Convenience method for outputting a field entry ("member") * that has the specified numeric value. Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeNumber(value);
     *
*/ public final void writeNumberField(String fieldName, int value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeNumber(value); } /** * Convenience method for outputting a field entry ("member") * that has the specified numeric value. Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeNumber(value);
     *
*/ public final void writeNumberField(String fieldName, long value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeNumber(value); } /** * Convenience method for outputting a field entry ("member") * that has the specified numeric value. Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeNumber(value);
     *
*/ public final void writeNumberField(String fieldName, double value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeNumber(value); } /** * Convenience method for outputting a field entry ("member") * that has the specified numeric value. Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeNumber(value);
     *
*/ public final void writeNumberField(String fieldName, float value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeNumber(value); } /** * Convenience method for outputting a field entry ("member") * that has the specified numeric value. * Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeNumber(value);
     *
*/ public final void writeNumberField(String fieldName, BigDecimal value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeNumber(value); } /** * Convenience method for outputting a field entry ("member") * that contains specified data in base64-encoded form. * Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeBinary(value);
     *
*/ public final void writeBinaryField(String fieldName, byte[] data) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeBinary(data); } /** * Convenience method for outputting a field entry ("member") * (that will contain a JSON Array value), and the START_ARRAY marker. * Equivalent to: *
     *  writeFieldName(fieldName);
     *  writeStartArray();
     *
*

* Note: caller still has to take care to close the array * (by calling {#link #writeEndArray}) after writing all values * of the value Array. */ public final void writeArrayFieldStart(String fieldName) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeStartArray(); } /** * Convenience method for outputting a field entry ("member") * (that will contain a JSON Object value), and the START_OBJECT marker. * Equivalent to: *

     *  writeFieldName(fieldName);
     *  writeStartObject();
     *
*

* Note: caller still has to take care to close the Object * (by calling {#link #writeEndObject}) after writing all * entries of the value Object. */ public final void writeObjectFieldStart(String fieldName) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeStartObject(); } /** * Convenience method for outputting a field entry ("member") * that has contents of specific Java object as its value. * Equivalent to: *

     *  writeFieldName(fieldName);
     *  writeObject(pojo);
     *
*/ public final void writeObjectField(String fieldName, Object pojo) throws IOException, JsonProcessingException { writeFieldName(fieldName); writeObject(pojo); } /* /********************************************************** /* Public API, copy-through methods /********************************************************** */ /** * Method for copying contents of the current event that * the given parser instance points to. * Note that the method will not copy any other events, * such as events contained within Json Array or Object structures. *

* Calling this method will not advance the given * parser, although it may cause parser to internally process * more data (if it lazy loads contents of value events, for example) */ public abstract void copyCurrentEvent(JsonParser jp) throws IOException, JsonProcessingException; /** * Method for copying contents of the current event * and following events that it encloses * the given parser instance points to. *

* So what constitutes enclosing? Here is the list of * events that have associated enclosed events that will * get copied: *

    *
  • {@link JsonToken#START_OBJECT}: * all events up to and including matching (closing) * {@link JsonToken#END_OBJECT} will be copied *
  • *
  • {@link JsonToken#START_ARRAY} * all events up to and including matching (closing) * {@link JsonToken#END_ARRAY} will be copied *
  • *
  • {@link JsonToken#FIELD_NAME} the logical value (which * can consist of a single scalar value; or a sequence of related * events for structured types (Json Arrays, Objects)) will * be copied along with the name itself. So essentially the * whole field entry (name and value) will be copied. *
  • *
*

* After calling this method, parser will point to the * last event that was copied. This will either be * the event parser already pointed to (if there were no * enclosed events), or the last enclosed event copied. */ public abstract void copyCurrentStructure(JsonParser jp) throws IOException, JsonProcessingException; /* /********************************************************** /* Public API, context access /********************************************************** */ /** * @return Context object that can give information about logical * position within generated json content. */ public abstract JsonStreamContext getOutputContext(); /* /********************************************************** /* Public API, buffer handling /********************************************************** */ /** * Method called to flush any buffered content to the underlying * target (output stream, writer), and to flush the target itself * as well. */ public abstract void flush() throws IOException; /** * Method that can be called to determine whether this generator * is closed or not. If it is closed, no more output can be done. */ public abstract boolean isClosed(); /* /********************************************************** /* Closeable implementation /********************************************************** */ /** * Method called to close this generator, so that no more content * can be written. *

* Whether the underlying target (stream, writer) gets closed depends * on whether this generator either manages the target (i.e. is the * only one with access to the target -- case if caller passes a * reference to the resource such as File, but not stream); or * has feature {@link Feature#AUTO_CLOSE_TARGET} enabled. * If either of above is true, the target is also closed. Otherwise * (not managing, feature not enabled), target is not closed. */ @Override public abstract void close() throws IOException; } jackson-src-1.9.2/src/java/org/codehaus/jackson/Base64Variant.java0000644000175000017500000003271211655120726025362 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson; import java.util.Arrays; /** * Abstract base class used to define specific details of which * variant of Base64 encoding/decoding is to be used. Although there is * somewhat standard basic version (so-called "MIME Base64"), other variants * exists, see Base64 Wikipedia entry for details. * * @author Tatu Saloranta * * @since 0.9.3 */ public final class Base64Variant { /** * Placeholder used by "no padding" variant, to be used when a character * value is needed. */ final static char PADDING_CHAR_NONE = '\0'; /** * Marker used to denote ascii characters that do not correspond * to a 6-bit value (in this variant), and is not used as a padding * character. */ public final static int BASE64_VALUE_INVALID = -1; /** * Marker used to denote ascii character (in decoding table) that * is the padding character using this variant (if any). */ public final static int BASE64_VALUE_PADDING = -2; /* /********************************************************** /* Encoding/decoding tables /********************************************************** */ /** * Decoding table used for base 64 decoding. */ private final int[] _asciiToBase64 = new int[128]; /** * Encoding table used for base 64 decoding when output is done * as characters. */ private final char[] _base64ToAsciiC = new char[64]; /** * Alternative encoding table used for base 64 decoding when output is done * as ascii bytes. */ private final byte[] _base64ToAsciiB = new byte[64]; /* /********************************************************** /* Other configuration /********************************************************** */ /** * Symbolic name of variant; used for diagnostics/debugging. */ final String _name; /** * Whether this variant uses padding or not. */ final boolean _usesPadding; /** * Characted used for padding, if any ({@link #PADDING_CHAR_NONE} if not). */ final char _paddingChar; /** * Maximum number of encoded base64 characters to output during encoding * before adding a linefeed, if line length is to be limited * ({@link java.lang.Integer#MAX_VALUE} if not limited). *

* Note: for some output modes (when writing attributes) linefeeds may * need to be avoided, and this value ignored. */ final int _maxLineLength; /* /********************************************************** /* Life-cycle /********************************************************** */ public Base64Variant(String name, String base64Alphabet, boolean usesPadding, char paddingChar, int maxLineLength) { _name = name; _usesPadding = usesPadding; _paddingChar = paddingChar; _maxLineLength = maxLineLength; // Ok and then we need to create codec tables. // First the main encoding table: int alphaLen = base64Alphabet.length(); if (alphaLen != 64) { throw new IllegalArgumentException("Base64Alphabet length must be exactly 64 (was "+alphaLen+")"); } // And then secondary encoding table and decoding table: base64Alphabet.getChars(0, alphaLen, _base64ToAsciiC, 0); Arrays.fill(_asciiToBase64, BASE64_VALUE_INVALID); for (int i = 0; i < alphaLen; ++i) { char alpha = _base64ToAsciiC[i]; _base64ToAsciiB[i] = (byte) alpha; _asciiToBase64[alpha] = i; } // Plus if we use padding, add that in too if (usesPadding) { _asciiToBase64[(int) paddingChar] = BASE64_VALUE_PADDING; } } /** * "Copy constructor" that can be used when the base alphabet is identical * to one used by another variant except for the maximum line length * (and obviously, name). */ public Base64Variant(Base64Variant base, String name, int maxLineLength) { this(base, name, base._usesPadding, base._paddingChar, maxLineLength); } /** * "Copy constructor" that can be used when the base alphabet is identical * to one used by another variant, but other details (padding, maximum * line length) differ */ public Base64Variant(Base64Variant base, String name, boolean usesPadding, char paddingChar, int maxLineLength) { _name = name; byte[] srcB = base._base64ToAsciiB; System.arraycopy(srcB, 0, this._base64ToAsciiB, 0, srcB.length); char[] srcC = base._base64ToAsciiC; System.arraycopy(srcC, 0, this._base64ToAsciiC, 0, srcC.length); int[] srcV = base._asciiToBase64; System.arraycopy(srcV, 0, this._asciiToBase64, 0, srcV.length); _usesPadding = usesPadding; _paddingChar = paddingChar; _maxLineLength = maxLineLength; } /* /********************************************************** /* Public accessors /********************************************************** */ public String getName() { return _name; } public boolean usesPadding() { return _usesPadding; } public boolean usesPaddingChar(char c) { return c == _paddingChar; } public boolean usesPaddingChar(int ch) { return ch == (int) _paddingChar; } public char getPaddingChar() { return _paddingChar; } public byte getPaddingByte() { return (byte)_paddingChar; } public int getMaxLineLength() { return _maxLineLength; } /* /********************************************************** /* Decoding support /********************************************************** */ /** * @return 6-bit decoded value, if valid character; */ public int decodeBase64Char(char c) { int ch = (int) c; return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; } public int decodeBase64Char(int ch) { return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; } public int decodeBase64Byte(byte b) { int ch = (int) b; return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; } /* /********************************************************** /* Encoding support /********************************************************** */ public char encodeBase64BitsAsChar(int value) { /* Let's assume caller has done necessary checks; this * method must be fast and inlinable */ return _base64ToAsciiC[value]; } /** * Method that encodes given right-aligned (LSB) 24-bit value * into 4 base64 characters, stored in given result buffer. */ public int encodeBase64Chunk(int b24, char[] buffer, int ptr) { buffer[ptr++] = _base64ToAsciiC[(b24 >> 18) & 0x3F]; buffer[ptr++] = _base64ToAsciiC[(b24 >> 12) & 0x3F]; buffer[ptr++] = _base64ToAsciiC[(b24 >> 6) & 0x3F]; buffer[ptr++] = _base64ToAsciiC[b24 & 0x3F]; return ptr; } public void encodeBase64Chunk(StringBuilder sb, int b24) { sb.append(_base64ToAsciiC[(b24 >> 18) & 0x3F]); sb.append(_base64ToAsciiC[(b24 >> 12) & 0x3F]); sb.append(_base64ToAsciiC[(b24 >> 6) & 0x3F]); sb.append(_base64ToAsciiC[b24 & 0x3F]); } /** * Method that outputs partial chunk (which only encodes one * or two bytes of data). Data given is still aligned same as if * it as full data; that is, missing data is at the "right end" * (LSB) of int. * * @param outputBytes Number of encoded bytes included (either 1 or 2) */ public int encodeBase64Partial(int bits, int outputBytes, char[] buffer, int outPtr) { buffer[outPtr++] = _base64ToAsciiC[(bits >> 18) & 0x3F]; buffer[outPtr++] = _base64ToAsciiC[(bits >> 12) & 0x3F]; if (_usesPadding) { buffer[outPtr++] = (outputBytes == 2) ? _base64ToAsciiC[(bits >> 6) & 0x3F] : _paddingChar; buffer[outPtr++] = _paddingChar; } else { if (outputBytes == 2) { buffer[outPtr++] = _base64ToAsciiC[(bits >> 6) & 0x3F]; } } return outPtr; } public void encodeBase64Partial(StringBuilder sb, int bits, int outputBytes) { sb.append(_base64ToAsciiC[(bits >> 18) & 0x3F]); sb.append(_base64ToAsciiC[(bits >> 12) & 0x3F]); if (_usesPadding) { sb.append((outputBytes == 2) ? _base64ToAsciiC[(bits >> 6) & 0x3F] : _paddingChar); sb.append(_paddingChar); } else { if (outputBytes == 2) { sb.append(_base64ToAsciiC[(bits >> 6) & 0x3F]); } } } public byte encodeBase64BitsAsByte(int value) { // As with above, assuming it is 6-bit value return _base64ToAsciiB[value]; } /** * Method that encodes given right-aligned (LSB) 24-bit value * into 4 base64 bytes (ascii), stored in given result buffer. */ public int encodeBase64Chunk(int b24, byte[] buffer, int ptr) { buffer[ptr++] = _base64ToAsciiB[(b24 >> 18) & 0x3F]; buffer[ptr++] = _base64ToAsciiB[(b24 >> 12) & 0x3F]; buffer[ptr++] = _base64ToAsciiB[(b24 >> 6) & 0x3F]; buffer[ptr++] = _base64ToAsciiB[b24 & 0x3F]; return ptr; } /** * Method that outputs partial chunk (which only encodes one * or two bytes of data). Data given is still aligned same as if * it as full data; that is, missing data is at the "right end" * (LSB) of int. * * @param outputBytes Number of encoded bytes included (either 1 or 2) */ public int encodeBase64Partial(int bits, int outputBytes, byte[] buffer, int outPtr) { buffer[outPtr++] = _base64ToAsciiB[(bits >> 18) & 0x3F]; buffer[outPtr++] = _base64ToAsciiB[(bits >> 12) & 0x3F]; if (_usesPadding) { byte pb = (byte) _paddingChar; buffer[outPtr++] = (outputBytes == 2) ? _base64ToAsciiB[(bits >> 6) & 0x3F] : pb; buffer[outPtr++] = pb; } else { if (outputBytes == 2) { buffer[outPtr++] = _base64ToAsciiB[(bits >> 6) & 0x3F]; } } return outPtr; } /** * Convenience method for converting given byte array as base64 encoded * String using this variant's settings. * Resulting value is "raw", that is, not enclosed in double-quotes. * * @param input Byte array to encode * * @since 1.6 */ public String encode(byte[] input) { return encode(input, false); } /** * Convenience method for converting given byte array as base64 encoded * String using this variant's settings, optionally enclosed in * double-quotes. * * @param input Byte array to encode * @param addQuotes Whether to surround resulting value in double quotes * or not * * @since 1.6 */ public String encode(byte[] input, boolean addQuotes) { int inputEnd = input.length; StringBuilder sb; { // let's approximate... 33% overhead, ~= 3/8 (0.375) int outputLen = inputEnd + (inputEnd >> 2) + (inputEnd >> 3); sb = new StringBuilder(outputLen); } if (addQuotes) { sb.append('"'); } int chunksBeforeLF = getMaxLineLength() >> 2; // Ok, first we loop through all full triplets of data: int inputPtr = 0; int safeInputEnd = inputEnd-3; // to get only full triplets while (inputPtr <= safeInputEnd) { // First, mash 3 bytes into lsb of 32-bit int int b24 = ((int) input[inputPtr++]) << 8; b24 |= ((int) input[inputPtr++]) & 0xFF; b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF); encodeBase64Chunk(sb, b24); if (--chunksBeforeLF <= 0) { // note: must quote in JSON value, so not really useful... sb.append('\\'); sb.append('n'); chunksBeforeLF = getMaxLineLength() >> 2; } } // And then we may have 1 or 2 leftover bytes to encode int inputLeft = inputEnd - inputPtr; // 0, 1 or 2 if (inputLeft > 0) { // yes, but do we have room for output? int b24 = ((int) input[inputPtr++]) << 16; if (inputLeft == 2) { b24 |= (((int) input[inputPtr++]) & 0xFF) << 8; } encodeBase64Partial(sb, b24, inputLeft); } if (addQuotes) { sb.append('"'); } return sb.toString(); } /* /********************************************************** /* other methods /********************************************************** */ @Override public String toString() { return _name; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/Base64Variants.java0000644000175000017500000000726111655120726025546 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson; /** * Container for commonly used Base64 variants. * * @author Tatu Saloranta */ public final class Base64Variants { final static String STD_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * This variant is what most people would think of "the standard" * Base64 encoding. *

* See wikipedia Base64 entry for details. *

* Note that although this can be thought of as the standard variant, * it is not the default for Jackson: no-linefeeds alternative * is because of JSON requirement of escaping all linefeeds. */ public final static Base64Variant MIME; static { MIME = new Base64Variant("MIME", STD_BASE64_ALPHABET, true, '=', 76); } /** * Slightly non-standard modification of {@link #MIME} which does not * use linefeeds (max line length set to infinite). Useful when linefeeds * wouldn't work well (possibly in attributes), or for minor space savings * (save 1 linefeed per 76 data chars, ie. ~1.4% savings). */ public final static Base64Variant MIME_NO_LINEFEEDS; static { MIME_NO_LINEFEEDS = new Base64Variant(MIME, "MIME-NO-LINEFEEDS", Integer.MAX_VALUE); } /** * This variant is the one that predates {@link #MIME}: it is otherwise * identical, except that it mandates shorter line length. */ public final static Base64Variant PEM = new Base64Variant(MIME, "PEM", true, '=', 64); /** * This non-standard variant is usually used when encoded data needs to be * passed via URLs (such as part of GET request). It differs from the * base {@link #MIME} variant in multiple ways. * First, no padding is used: this also means that it generally can not * be written in multiple separate but adjacent chunks (which would not * be the usual use case in any case). Also, no linefeeds are used (max * line length set to infinite). And finally, two characters (plus and * slash) that would need quoting in URLs are replaced with more * optimal alternatives (hyphen and underscore, respectively). */ public final static Base64Variant MODIFIED_FOR_URL; static { StringBuffer sb = new StringBuffer(STD_BASE64_ALPHABET); // Replace plus with hyphen, slash with underscore (and no padding) sb.setCharAt(sb.indexOf("+"), '-'); sb.setCharAt(sb.indexOf("/"), '_'); /* And finally, let's not split lines either, wouldn't work too * well with URLs */ MODIFIED_FOR_URL = new Base64Variant("MODIFIED-FOR-URL", sb.toString(), false, Base64Variant.PADDING_CHAR_NONE, Integer.MAX_VALUE); } /** * Method used to get the default variant ("MIME_NO_LINEFEEDS") for cases * where caller does not explicitly specify the variant. * We will prefer no-linefeed version because linefeeds in JSON values * must be escaped, making linefeed-containing variants sub-optimal. */ public static Base64Variant getDefaultVariant() { return MIME_NO_LINEFEEDS; } } jackson-src-1.9.2/src/java/org/codehaus/jackson/Version.java0000644000175000017500000000505111655120726024432 0ustar jamespagejamespagepackage org.codehaus.jackson; /** * Object that encapsulates version information of a component, * and is return by {@link Versioned#version}. * * @since 1.6 */ public class Version implements Comparable { private final static Version UNKNOWN_VERSION = new Version(0, 0, 0, null); protected final int _majorVersion; protected final int _minorVersion; protected final int _patchLevel; /** * Additional information for snapshot versions; null for non-snapshot * (release) versions. */ protected final String _snapshotInfo; public Version(int major, int minor, int patchLevel, String snapshotInfo) { _majorVersion = major; _minorVersion = minor; _patchLevel = patchLevel; _snapshotInfo = snapshotInfo; } /** * Method returns canonical "not known" version, which is used as version * in cases where actual version information is not known (instead of null). */ public static Version unknownVersion() { return UNKNOWN_VERSION; } public boolean isUknownVersion() { return (this == UNKNOWN_VERSION); } public boolean isSnapshot() { return (_snapshotInfo != null && _snapshotInfo.length() > 0); } public int getMajorVersion() { return _majorVersion; } public int getMinorVersion() { return _minorVersion; } public int getPatchLevel() { return _patchLevel; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(_majorVersion).append('.'); sb.append(_minorVersion).append('.'); sb.append(_patchLevel); if (isSnapshot()) { sb.append('-').append(_snapshotInfo); } return sb.toString(); } @Override public int hashCode() { return _majorVersion + _minorVersion + _patchLevel; } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) return false; Version other = (Version) o; return (other._majorVersion == _majorVersion) && (other._minorVersion == _minorVersion) && (other._patchLevel == _patchLevel); } @Override public int compareTo(Version other) { int diff = _majorVersion - other._majorVersion; if (diff == 0) { diff = _minorVersion - other._minorVersion; if (diff == 0) { diff = _patchLevel - other._patchLevel; } } return diff; } } jackson-src-1.9.2/src/VERSION.txt0000644000175000017500000000001211655120726017065 0ustar jamespagejamespage@VERSION@ jackson-src-1.9.2/src/mapper/0000755000175000017500000000000011655120726016472 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/0000755000175000017500000000000011655120726017413 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/0000755000175000017500000000000011655120726020202 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/0000755000175000017500000000000011655120726021775 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/0000755000175000017500000000000011655120726023425 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/schema/0000755000175000017500000000000011672662540024671 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/schema/JsonSchema.java0000644000175000017500000000421111655120726027560 0ustar jamespagejamespagepackage org.codehaus.jackson.schema; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.annotate.JsonCreator; import org.codehaus.jackson.annotate.JsonValue; import org.codehaus.jackson.node.ObjectNode; import org.codehaus.jackson.node.JsonNodeFactory; /** * A {@link org.codehaus.jackson.JsonNode} that represents a JSON-Schema instance. * * @author Ryan Heaton * @see JSON Schema */ public class JsonSchema { private final ObjectNode schema; /** * Main constructor for schema instances. *

* This is the creator constructor used by Jackson itself when * deserializing instances. It is so-called delegating creator, * meaning that its argument will be bound by Jackson before * constructor gets called. */ @JsonCreator public JsonSchema(ObjectNode schema) { this.schema = schema; } /** * Method for accessing root JSON object of the contained schema. *

* Note: this method is specified with {@link JsonValue} annotation * to represent serialization to use; same as if explicitly * serializing returned object. * * @return Root node of the schema tree */ @JsonValue public ObjectNode getSchemaNode() { return schema; } @Override public String toString() { return this.schema.toString(); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (!(o instanceof JsonSchema)) return false; JsonSchema other = (JsonSchema) o; if (schema == null) { return other.schema == null; } return schema.equals(other.schema); } /** * Get the default schema node. * * @return The default schema node. */ public static JsonNode getDefaultSchemaNode() { ObjectNode objectNode = JsonNodeFactory.instance.objectNode(); objectNode.put("type", "any"); // "required" is false by default, no need to include //objectNode.put("required", false); return objectNode; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/schema/package-info.java0000644000175000017500000000026011655120726030052 0ustar jamespagejamespage/** * Classes needed for JSON schema support (currently just ability * to generate schemas using serialization part of data mapping) */ package org.codehaus.jackson.schema; jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/schema/JsonSerializableSchema.java0000644000175000017500000000276011655120726032116 0ustar jamespagejamespagepackage org.codehaus.jackson.schema; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Retention; import java.lang.annotation.ElementType; import java.lang.annotation.Target; import org.codehaus.jackson.annotate.JacksonAnnotation; /** * Annotation that can be used to define JSON Schema definition for * the annotated class. *

* Note that annotation is often not needed: for example, regular * Jackson beans that Jackson can introspect can be used without * annotations, to produce JSON schema definition. * * @author Ryan Heaton */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonSerializableSchema { /** * The schema type for this JsonSerializable instance. * Possible values: "string", "number", "boolean", "object", "array", "null", "any" * * @return The schema type for this JsonSerializable instance. */ String schemaType() default "any"; /** * If the schema type is "object", the node that defines the properties of the object. * * @return The node representing the schema properties, or "##irrelevant" if irrelevant. */ String schemaObjectPropertiesDefinition() default "##irrelevant"; /** * If the schema type if "array", the node that defines the schema for the items in the array. * * @return The schema for the items in the array, or "##irrelevant" if irrelevant. */ String schemaItemDefinition() default "##irrelevant"; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/schema/SchemaAware.java0000644000175000017500000000132611655120726027712 0ustar jamespagejamespagepackage org.codehaus.jackson.schema; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.JsonMappingException; import java.lang.reflect.Type; /** * Marker interface for schema-aware serializers. * * @author Ryan Heaton */ public interface SchemaAware { /** * Get the representation of the schema to which this serializer will conform. * * @param provider The serializer provider. * @param typeHint A hint about the type. * @return Json-schema for this serializer. */ JsonNode getSchema(SerializerProvider provider, Type typeHint) throws JsonMappingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/0000755000175000017500000000000011672662540024356 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/NullNode.java0000644000175000017500000000230611655120726026736 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; /** * This singleton value class is used to contain explicit JSON null * value. */ public final class NullNode extends ValueNode { // // Just need a fly-weight singleton public final static NullNode instance = new NullNode(); private NullNode() { } public static NullNode getInstance() { return instance; } @Override public JsonToken asToken() { return JsonToken.VALUE_NULL; } @Override public boolean isNull() { return true; } @Override public String asText() { return "null"; } @Override public int asInt(int defaultValue) { return 0; } @Override public long asLong(long defaultValue) { return 0L; } @Override public double asDouble(double defaultValue) { return 0.0; } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeNull(); } @Override public boolean equals(Object o) { return (o == this); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/NumericNode.java0000644000175000017500000000311211655120726027422 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.JsonParser; /** * Intermediate value node used for numeric nodes. */ public abstract class NumericNode extends ValueNode { protected NumericNode() { } @Override public final boolean isNumber() { return true; } // // // Let's re-abstract so sub-classes handle them @Override public abstract JsonParser.NumberType getNumberType(); @Override public abstract Number getNumberValue(); @Override public abstract int getIntValue(); @Override public abstract long getLongValue(); @Override public abstract double getDoubleValue(); @Override public abstract BigDecimal getDecimalValue(); @Override public abstract BigInteger getBigIntegerValue(); /* /********************************************************** /* General type coercions /********************************************************** */ @Override public abstract String asText(); @Override public int asInt() { return getIntValue(); } @Override public int asInt(int defaultValue) { return getIntValue(); } @Override public long asLong() { return getLongValue(); } @Override public long asLong(long defaultValue) { return getLongValue(); } @Override public double asDouble() { return getDoubleValue(); } @Override public double asDouble(double defaultValue) { return getDoubleValue(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/TextNode.java0000644000175000017500000002267211655120726026760 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.io.NumberInput; import org.codehaus.jackson.util.ByteArrayBuilder; import org.codehaus.jackson.util.CharTypes; /** * Value node that contains a text value. */ public final class TextNode extends ValueNode { final static int INT_SPACE = ' '; final static TextNode EMPTY_STRING_NODE = new TextNode(""); final String _value; public TextNode(String v) { _value = v; } /** * Factory method that should be used to construct instances. * For some common cases, can reuse canonical instances: currently * this is the case for empty Strings, in future possible for * others as well. If null is passed, will return null. * * @return Resulting {@link TextNode} object, if v * is NOT null; null if it is. */ public static TextNode valueOf(String v) { if (v == null) { return null; } if (v.length() == 0) { return EMPTY_STRING_NODE; } return new TextNode(v); } @Override public JsonToken asToken() { return JsonToken.VALUE_STRING; } /** * Yes indeed it is textual */ @Override public boolean isTextual() { return true; } @Override public String getTextValue() { return _value; } /** * Method for accessing textual contents assuming they were * base64 encoded; if so, they are decoded and resulting binary * data is returned. */ public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { ByteArrayBuilder builder = new ByteArrayBuilder(100); final String str = _value; int ptr = 0; int len = str.length(); main_loop: while (ptr < len) { // first, we'll skip preceding white space, if any char ch; do { ch = str.charAt(ptr++); if (ptr >= len) { break main_loop; } } while (ch <= INT_SPACE); int bits = b64variant.decodeBase64Char(ch); if (bits < 0) { _reportInvalidBase64(b64variant, ch, 0); } int decodedData = bits; // then second base64 char; can't get padding yet, nor ws if (ptr >= len) { _reportBase64EOF(); } ch = str.charAt(ptr++); bits = b64variant.decodeBase64Char(ch); if (bits < 0) { _reportInvalidBase64(b64variant, ch, 1); } decodedData = (decodedData << 6) | bits; // third base64 char; can be padding, but not ws if (ptr >= len) { // but as per [JACKSON-631] can be end-of-input, iff not using padding if (!b64variant.usesPadding()) { // Got 12 bits, only need 8, need to shift decodedData >>= 4; builder.append(decodedData); break; } _reportBase64EOF(); } ch = str.charAt(ptr++); bits = b64variant.decodeBase64Char(ch); // First branch: can get padding (-> 1 byte) if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { _reportInvalidBase64(b64variant, ch, 2); } // Ok, must get padding if (ptr >= len) { _reportBase64EOF(); } ch = str.charAt(ptr++); if (!b64variant.usesPaddingChar(ch)) { _reportInvalidBase64(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'"); } // Got 12 bits, only need 8, need to shift decodedData >>= 4; builder.append(decodedData); continue; } // Nope, 2 or 3 bytes decodedData = (decodedData << 6) | bits; // fourth and last base64 char; can be padding, but not ws if (ptr >= len) { // but as per [JACKSON-631] can be end-of-input, iff not using padding if (!b64variant.usesPadding()) { decodedData >>= 2; builder.appendTwoBytes(decodedData); break; } _reportBase64EOF(); } ch = str.charAt(ptr++); bits = b64variant.decodeBase64Char(ch); if (bits < 0) { if (bits != Base64Variant.BASE64_VALUE_PADDING) { _reportInvalidBase64(b64variant, ch, 3); } decodedData >>= 2; builder.appendTwoBytes(decodedData); } else { // otherwise, our triple is now complete decodedData = (decodedData << 6) | bits; builder.appendThreeBytes(decodedData); } } return builder.toByteArray(); } @Override public byte[] getBinaryValue() throws IOException { return getBinaryValue(Base64Variants.getDefaultVariant()); } /* /********************************************************** /* General type coercions /********************************************************** */ @Override public String asText() { return _value; } // note: neither fast nor elegant, but these work for now: @Override public boolean asBoolean(boolean defaultValue) { if (_value != null) { if ("true".equals(_value.trim())) { return true; } } return defaultValue; } @Override public int asInt(int defaultValue) { return NumberInput.parseAsInt(_value, defaultValue); } @Override public long asLong(long defaultValue) { return NumberInput.parseAsLong(_value, defaultValue); } @Override public double asDouble(double defaultValue) { return NumberInput.parseAsDouble(_value, defaultValue); } /* /********************************************************** /* Serialization /********************************************************** */ @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { if (_value == null) { jg.writeNull(); } else { jg.writeString(_value); } } /* /********************************************************** /* Overridden standard methods /********************************************************** */ @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } return ((TextNode) o)._value.equals(_value); } @Override public int hashCode() { return _value.hashCode(); } /** * Different from other values, Strings need quoting */ @Override public String toString() { int len = _value.length(); len = len + 2 + (len >> 4); StringBuilder sb = new StringBuilder(len); appendQuoted(sb, _value); return sb.toString(); } protected static void appendQuoted(StringBuilder sb, String content) { sb.append('"'); CharTypes.appendQuoted(sb, content); sb.append('"'); } /* /********************************************************** /* Helper methods /********************************************************** */ protected void _reportInvalidBase64(Base64Variant b64variant, char ch, int bindex) throws JsonParseException { _reportInvalidBase64(b64variant, ch, bindex, null); } /** * @param bindex Relative index within base64 character unit; between 0 * and 3 (as unit has exactly 4 characters) */ protected void _reportInvalidBase64(Base64Variant b64variant, char ch, int bindex, String msg) throws JsonParseException { String base; if (ch <= INT_SPACE) { base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units"; } else if (b64variant.usesPaddingChar(ch)) { base = "Unexpected padding character ('"+b64variant.getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character"; } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) { // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level) base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content"; } else { base = "Illegal character '"+ch+"' (code 0x"+Integer.toHexString(ch)+") in base64 content"; } if (msg != null) { base = base + ": " + msg; } throw new JsonParseException(base, JsonLocation.NA); } protected void _reportBase64EOF() throws JsonParseException { throw new JsonParseException("Unexpected end-of-String when base64 content", JsonLocation.NA); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/BooleanNode.java0000644000175000017500000000405111655120726027402 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; /** * This concrete value class is used to contain boolean (true / false) * values. Only two instances are ever created, to minimize memory * usage */ public final class BooleanNode extends ValueNode { // // Just need two instances... public final static BooleanNode TRUE = new BooleanNode(); public final static BooleanNode FALSE = new BooleanNode(); private BooleanNode() { } public static BooleanNode getTrue() { return TRUE; } public static BooleanNode getFalse() { return FALSE; } public static BooleanNode valueOf(boolean b) { return b ? TRUE : FALSE; } // Interesting... two choices... @Override public JsonToken asToken() { return (this == TRUE) ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE; } @Override public boolean isBoolean() { return true; } @Override public boolean getBooleanValue() { return (this == TRUE); } @Override public String asText() { return (this == TRUE) ? "true" : "false"; } @Override public boolean asBoolean() { return (this == TRUE); } @Override public boolean asBoolean(boolean defaultValue) { return (this == TRUE); } @Override public int asInt(int defaultValue) { return (this == TRUE) ? 1 : 0; } @Override public long asLong(long defaultValue) { return (this == TRUE) ? 1L : 0L; } @Override public double asDouble(double defaultValue) { return (this == TRUE) ? 1.0 : 0.0; } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeBoolean(this == TRUE); } @Override public boolean equals(Object o) { /* Since there are only ever two instances in existence * can do identity comparison */ return (o == this); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/IntNode.java0000644000175000017500000000610011655120726026552 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.io.NumberOutput; import org.codehaus.jackson.map.SerializerProvider; /** * Numeric node that contains simple 32-bit integer values. */ public final class IntNode extends NumericNode { // // // Let's cache small set of common value final static int MIN_CANONICAL = -1; final static int MAX_CANONICAL = 10; private final static IntNode[] CANONICALS; static { int count = MAX_CANONICAL - MIN_CANONICAL + 1; CANONICALS = new IntNode[count]; for (int i = 0; i < count; ++i) { CANONICALS[i] = new IntNode(MIN_CANONICAL + i); } } /** * Integer value this node contains */ final int _value; /* ************************************************ * Construction ************************************************ */ public IntNode(int v) { _value = v; } public static IntNode valueOf(int i) { if (i > MAX_CANONICAL || i < MIN_CANONICAL) return new IntNode(i); return CANONICALS[i - MIN_CANONICAL]; } /* /********************************************************** /* BaseJsonNode extended API /********************************************************** */ @Override public JsonToken asToken() { return JsonToken.VALUE_NUMBER_INT; } @Override public JsonParser.NumberType getNumberType() { return JsonParser.NumberType.INT; } /* /********************************************************** /* Overrridden JsonNode methods /********************************************************** */ @Override public boolean isIntegralNumber() { return true; } @Override public boolean isInt() { return true; } @Override public Number getNumberValue() { return Integer.valueOf(_value); } @Override public int getIntValue() { return _value; } @Override public long getLongValue() { return (long) _value; } @Override public double getDoubleValue() { return (double) _value; } @Override public BigDecimal getDecimalValue() { return BigDecimal.valueOf(_value); } @Override public BigInteger getBigIntegerValue() { return BigInteger.valueOf(_value); } @Override public String asText() { return NumberOutput.toString(_value); } @Override public boolean asBoolean(boolean defaultValue) { return _value != 0; } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeNumber(_value); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } return ((IntNode) o)._value == _value; } @Override public int hashCode() { return _value; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/JsonNodeFactory.java0000644000175000017500000001644411655120726030275 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.math.BigDecimal; import java.math.BigInteger; /** * Base class that specifies methods for getting access to * Node instances (newly constructed, or shared, depending * on type), as well as basic implementation of the methods. * Designed to be sub-classed if extended functionality (additions * to behavior of node types, mostly) is needed. */ public class JsonNodeFactory { /** * Default singleton instance that construct "standard" node instances: * given that this class is stateless, a globally shared singleton * can be used. */ public final static JsonNodeFactory instance = new JsonNodeFactory(); protected JsonNodeFactory() { } /* /********************************************************** /* Factory methods for literal values /********************************************************** */ /** * Factory method for getting an instance of JSON boolean value * (either literal 'true' or 'false') */ public BooleanNode booleanNode(boolean v) { return v ? BooleanNode.getTrue() : BooleanNode.getFalse(); } /** * Factory method for getting an instance of JSON null node (which * represents literal null value) */ public NullNode nullNode() { return NullNode.getInstance(); } /* /********************************************************** /* Factory methods for numeric values /********************************************************** */ /** * Factory method for getting an instance of JSON numeric value * that expresses given 8-bit value */ public NumericNode numberNode(byte v) { return IntNode.valueOf(v); } /** * Alternate factory method that will handle wrapper value, which may * be null. * Due to possibility of null, returning type is not guaranteed to be * {@link NumericNode}, but just {@link ValueNode}. * * @since 1.9 */ public ValueNode numberNode(Byte value) { return (value == null) ? nullNode() : IntNode.valueOf(value.intValue()); } /** * Factory method for getting an instance of JSON numeric value * that expresses given 16-bit integer value */ public NumericNode numberNode(short v) { return IntNode.valueOf(v); } /** * Alternate factory method that will handle wrapper value, which may * be null. * Due to possibility of null, returning type is not guaranteed to be * {@link NumericNode}, but just {@link ValueNode}. * * @since 1.9 */ public ValueNode numberNode(Short value) { return (value == null) ? nullNode() : IntNode.valueOf(value.shortValue()); } /** * Factory method for getting an instance of JSON numeric value * that expresses given 32-bit integer value */ public NumericNode numberNode(int v) { return IntNode.valueOf(v); } /** * Alternate factory method that will handle wrapper value, which may * be null. * Due to possibility of null, returning type is not guaranteed to be * {@link NumericNode}, but just {@link ValueNode}. * * @since 1.9 */ public ValueNode numberNode(Integer value) { return (value == null) ? nullNode() : IntNode.valueOf(value.intValue()); } /** * Factory method for getting an instance of JSON numeric value * that expresses given 64-bit integer value */ public NumericNode numberNode(long v) { return LongNode.valueOf(v); } /** * Alternate factory method that will handle wrapper value, which may * be null. * Due to possibility of null, returning type is not guaranteed to be * {@link NumericNode}, but just {@link ValueNode}. * * @since 1.9 */ public ValueNode numberNode(Long value) { return (value == null) ? nullNode() : LongNode.valueOf(value.longValue()); } /** * Factory method for getting an instance of JSON numeric value * that expresses given unlimited range integer value */ public NumericNode numberNode(BigInteger v) { return BigIntegerNode.valueOf(v); } /** * Factory method for getting an instance of JSON numeric value * that expresses given 32-bit floating point value */ public NumericNode numberNode(float v) { return DoubleNode.valueOf((double) v); } /** * Alternate factory method that will handle wrapper value, which may * be null. * Due to possibility of null, returning type is not guaranteed to be * {@link NumericNode}, but just {@link ValueNode}. * * @since 1.9 */ public ValueNode numberNode(Float value) { return (value == null) ? nullNode() : DoubleNode.valueOf(value.doubleValue()); } /** * Factory method for getting an instance of JSON numeric value * that expresses given 64-bit floating point value */ public NumericNode numberNode(double v) { return DoubleNode.valueOf(v); } /** * Alternate factory method that will handle wrapper value, which may * be null. * Due to possibility of null, returning type is not guaranteed to be * {@link NumericNode}, but just {@link ValueNode}. * * @since 1.9 */ public ValueNode numberNode(Double value) { return (value == null) ? nullNode() : DoubleNode.valueOf(value.doubleValue()); } /** * Factory method for getting an instance of JSON numeric value * that expresses given unlimited precision floating point value */ public NumericNode numberNode(BigDecimal v) { return DecimalNode.valueOf(v); } /* /********************************************************** /* Factory methods for textual values /********************************************************** */ /** * Factory method for constructing a node that represents JSON * String value */ public TextNode textNode(String text) { return TextNode.valueOf(text); } /** * Factory method for constructing a node that represents given * binary data, and will get serialized as equivalent base64-encoded * String value */ public BinaryNode binaryNode(byte[] data) { return BinaryNode.valueOf(data); } /** * Factory method for constructing a node that represents given * binary data, and will get serialized as equivalent base64-encoded * String value */ public BinaryNode binaryNode(byte[] data, int offset, int length) { return BinaryNode.valueOf(data, offset, length); } /* /********************************************************** /* Factory method for structured values /********************************************************** */ /** * Factory method for constructing an empty JSON Array node */ public ArrayNode arrayNode() { return new ArrayNode(this); } /** * Factory method for constructing an empty JSON Object ("struct") node */ public ObjectNode objectNode() { return new ObjectNode(this); } /** * Factory method for constructing a wrapper for POJO * ("Plain Old Java Object") objects; these will get serialized * using data binding, usually as JSON Objects, but in some * cases as JSON Strings or other node types. */ public POJONode POJONode(Object pojo) { return new POJONode(pojo); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/ObjectNode.java0000644000175000017500000004744211655120726027244 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.util.*; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.TypeSerializer; /** * Node that maps to JSON Object structures in JSON content. */ public class ObjectNode extends ContainerNode { protected LinkedHashMap _children = null; public ObjectNode(JsonNodeFactory nc) { super(nc); } /* /********************************************************** /* Implementation of core JsonNode API /********************************************************** */ @Override public JsonToken asToken() { return JsonToken.START_OBJECT; } @Override public boolean isObject() { return true; } @Override public int size() { return (_children == null) ? 0 : _children.size(); } @Override public Iterator getElements() { return (_children == null) ? NoNodesIterator.instance() : _children.values().iterator(); } @Override public JsonNode get(int index) { return null; } @Override public JsonNode get(String fieldName) { if (_children != null) { return _children.get(fieldName); } return null; } @Override public Iterator getFieldNames() { return (_children == null) ? NoStringsIterator.instance() : _children.keySet().iterator(); } @Override public JsonNode path(int index) { return MissingNode.getInstance(); } @Override public JsonNode path(String fieldName) { if (_children != null) { JsonNode n = _children.get(fieldName); if (n != null) { return n; } } return MissingNode.getInstance(); } /** * Method to use for accessing all fields (with both names * and values) of this JSON Object. */ @Override public Iterator> getFields() { if (_children == null) { return NoFieldsIterator.instance; } return _children.entrySet().iterator(); } @Override public ObjectNode with(String propertyName) { if (_children == null) { _children = new LinkedHashMap(); } else { JsonNode n = _children.get(propertyName); if (n != null) { if (n instanceof ObjectNode) { return (ObjectNode) n; } throw new UnsupportedOperationException("Property '"+propertyName +"' has value that is not of type ObjectNode (but " +n.getClass().getName()+")"); } } ObjectNode result = objectNode(); _children.put(propertyName, result); return result; } /* /********************************************************** /* Public API, finding value nodes /********************************************************** */ @Override public JsonNode findValue(String fieldName) { if (_children != null) { for (Map.Entry entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { return entry.getValue(); } JsonNode value = entry.getValue().findValue(fieldName); if (value != null) { return value; } } } return null; } @Override public List findValues(String fieldName, List foundSoFar) { if (_children != null) { for (Map.Entry entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { if (foundSoFar == null) { foundSoFar = new ArrayList(); } foundSoFar.add(entry.getValue()); } else { // only add children if parent not added foundSoFar = entry.getValue().findValues(fieldName, foundSoFar); } } } return foundSoFar; } @Override public List findValuesAsText(String fieldName, List foundSoFar) { if (_children != null) { for (Map.Entry entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { if (foundSoFar == null) { foundSoFar = new ArrayList(); } foundSoFar.add(entry.getValue().asText()); } else { // only add children if parent not added foundSoFar = entry.getValue().findValuesAsText(fieldName, foundSoFar); } } } return foundSoFar; } @Override public ObjectNode findParent(String fieldName) { if (_children != null) { for (Map.Entry entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { return this; } JsonNode value = entry.getValue().findParent(fieldName); if (value != null) { return (ObjectNode) value; } } } return null; } @Override public List findParents(String fieldName, List foundSoFar) { if (_children != null) { for (Map.Entry entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { if (foundSoFar == null) { foundSoFar = new ArrayList(); } foundSoFar.add(this); } else { // only add children if parent not added foundSoFar = entry.getValue().findParents(fieldName, foundSoFar); } } } return foundSoFar; } /* /********************************************************** /* Public API, serialization /********************************************************** */ /** * Method that can be called to serialize this node and * all of its descendants using specified JSON generator. */ @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeStartObject(); if (_children != null) { for (Map.Entry en : _children.entrySet()) { jg.writeFieldName(en.getKey()); /* 17-Feb-2009, tatu: Can we trust that all nodes will always * extend BaseJsonNode? Or if not, at least implement * JsonSerializable? Let's start with former, change if * we must. */ ((BaseJsonNode) en.getValue()).serialize(jg, provider); } } jg.writeEndObject(); } @Override public void serializeWithType(JsonGenerator jg, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { typeSer.writeTypePrefixForObject(this, jg); if (_children != null) { for (Map.Entry en : _children.entrySet()) { jg.writeFieldName(en.getKey()); ((BaseJsonNode) en.getValue()).serialize(jg, provider); } } typeSer.writeTypeSuffixForObject(this, jg); } /* /********************************************************** /* Extended ObjectNode API, mutators, generic /********************************************************** */ /** * Method that will set specified field, replacing old value, * if any. * * @param value to set field to; if null, will be converted * to a {@link NullNode} first (to remove field entry, call * {@link #remove} instead) * * @return Old value of the field, if any; null if there was no * old value. */ public JsonNode put(String fieldName, JsonNode value) { if (value == null) { // let's not store 'raw' nulls but nodes value = nullNode(); } return _put(fieldName, value); } /** * Method for removing field entry from this ObjectNode. * Will return value of the field, if such field existed; * null if not. */ public JsonNode remove(String fieldName) { if (_children != null) { return _children.remove(fieldName); } return null; } /** * Method for removing specified field properties out of * this ObjectNode. * * @param fieldNames Names of fields to remove * * @return This ObjectNode after removing entries * * @since 1.6 */ public ObjectNode remove(Collection fieldNames) { if (_children != null) { for (String fieldName : fieldNames) { _children.remove(fieldName); } } return this; } /** * Method for removing all field properties, such that this * ObjectNode will contain no properties after call. */ @Override public ObjectNode removeAll() { _children = null; return this; } /** * Method for adding given properties to this object node, overriding * any existing values for those properties. * * @param properties Properties to add * * @return This node (to allow chaining) * * @since 1.3 */ public JsonNode putAll(Map properties) { if (_children == null) { _children = new LinkedHashMap(properties); } else { for (Map.Entry en : properties.entrySet()) { JsonNode n = en.getValue(); if (n == null) { n = nullNode(); } _children.put(en.getKey(), n); } } return this; } /** * Method for adding all properties of the given Object, overriding * any existing values for those properties. * * @param other Object of which properties to add to this object * * @return This node (to allow chaining) * * @since 1.3 */ public JsonNode putAll(ObjectNode other) { int len = other.size(); if (len > 0) { if (_children == null) { _children = new LinkedHashMap(len); } other.putContentsTo(_children); } return this; } /** * Method for removing all field properties out of this ObjectNode * except for ones specified in argument. * * @param fieldNames Fields to retain in this ObjectNode * * @return This ObjectNode (to allow call chaining) * * @since 1.6 */ public ObjectNode retain(Collection fieldNames) { if (_children != null) { Iterator> entries = _children.entrySet().iterator(); while (entries.hasNext()) { Map.Entry entry = entries.next(); if (!fieldNames.contains(entry.getKey())) { entries.remove(); } } } return this; } /** * Method for removing all field properties out of this ObjectNode * except for ones specified in argument. * * @param fieldNames Fields to retain in this ObjectNode * * @return This ObjectNode (to allow call chaining) * * @since 1.6 */ public ObjectNode retain(String... fieldNames) { return retain(Arrays.asList(fieldNames)); } /* /********************************************************** /* Extended ObjectNode API, mutators, typed /********************************************************** */ /** * Method that will construct an ArrayNode and add it as a * field of this ObjectNode, replacing old value, if any. * * @return Newly constructed ArrayNode (NOT the old value, * which could be of any type) */ public ArrayNode putArray(String fieldName) { ArrayNode n = arrayNode(); _put(fieldName, n); return n; } /** * Method that will construct an ObjectNode and add it as a * field of this ObjectNode, replacing old value, if any. * * @return Newly constructed ObjectNode (NOT the old value, * which could be of any type) */ public ObjectNode putObject(String fieldName) { ObjectNode n = objectNode(); _put(fieldName, n); return n; } public void putPOJO(String fieldName, Object pojo) { _put(fieldName, POJONode(pojo)); } public void putNull(String fieldName) { _put(fieldName, nullNode()); } /** * Method for setting value of a field to specified numeric value. */ public void put(String fieldName, int v) { _put(fieldName, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void put(String fieldName, Integer value) { if (value == null) { _put(fieldName, nullNode()); } else { _put(fieldName, numberNode(value.intValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void put(String fieldName, long v) { _put(fieldName, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void put(String fieldName, Long value) { if (value == null) { _put(fieldName, nullNode()); } else { _put(fieldName, numberNode(value.longValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void put(String fieldName, float v) { _put(fieldName, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void put(String fieldName, Float value) { if (value == null) { _put(fieldName, nullNode()); } else { _put(fieldName, numberNode(value.floatValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void put(String fieldName, double v) { _put(fieldName, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void put(String fieldName, Double value) { if (value == null) { _put(fieldName, nullNode()); } else { _put(fieldName, numberNode(value.doubleValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void put(String fieldName, BigDecimal v) { if (v == null) { putNull(fieldName); } else { _put(fieldName, numberNode(v)); } } /** * Method for setting value of a field to specified String value. */ public void put(String fieldName, String v) { if (v == null) { putNull(fieldName); } else { _put(fieldName, textNode(v)); } } /** * Method for setting value of a field to specified String value. */ public void put(String fieldName, boolean v) { _put(fieldName, booleanNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void put(String fieldName, Boolean value) { if (value == null) { _put(fieldName, nullNode()); } else { _put(fieldName, booleanNode(value.booleanValue())); } } /** * Method for setting value of a field to specified binary value */ public void put(String fieldName, byte[] v) { if (v == null) { _put(fieldName, nullNode()); } else { _put(fieldName, binaryNode(v)); } } /* /********************************************************** /* Package methods (for other node classes to use) /********************************************************** */ /** * @since 1.6 */ protected void putContentsTo(Map dst) { if (_children != null) { for (Map.Entry en : _children.entrySet()) { dst.put(en.getKey(), en.getValue()); } } } /* /********************************************************** /* Standard methods /********************************************************** */ @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { return false; } ObjectNode other = (ObjectNode) o; if (other.size() != size()) { return false; } if (_children != null) { for (Map.Entry en : _children.entrySet()) { String key = en.getKey(); JsonNode value = en.getValue(); JsonNode otherValue = other.get(key); if (otherValue == null || !otherValue.equals(value)) { return false; } } } return true; } @Override public int hashCode() { return (_children == null) ? -1 : _children.hashCode(); } @Override public String toString() { StringBuilder sb = new StringBuilder(32 + (size() << 4)); sb.append("{"); if (_children != null) { int count = 0; for (Map.Entry en : _children.entrySet()) { if (count > 0) { sb.append(","); } ++count; TextNode.appendQuoted(sb, en.getKey()); sb.append(':'); sb.append(en.getValue().toString()); } } sb.append("}"); return sb.toString(); } /* /********************************************************** /* Internal methods /********************************************************** */ private final JsonNode _put(String fieldName, JsonNode value) { if (_children == null) { _children = new LinkedHashMap(); } return _children.put(fieldName, value); } /* /********************************************************** /* Helper classes /********************************************************** */ /** * For efficiency, let's share the "no fields" iterator... */ protected static class NoFieldsIterator implements Iterator> { final static NoFieldsIterator instance = new NoFieldsIterator(); private NoFieldsIterator() { } @Override public boolean hasNext() { return false; } @Override public Map.Entry next() { throw new NoSuchElementException(); } @Override public void remove() { // or IllegalOperationException? throw new IllegalStateException(); } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/ContainerNode.java0000644000175000017500000001343411655120726027752 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.math.BigDecimal; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonToken; /** * This intermediate base class is used for all container nodes, * specifically, array and object nodes. */ public abstract class ContainerNode extends BaseJsonNode { /** * We will keep a reference to the Object (usually TreeMapper) * that can construct instances of nodes to add to this container * node. */ JsonNodeFactory _nodeFactory; protected ContainerNode(JsonNodeFactory nc) { _nodeFactory = nc; } @Override public boolean isContainerNode() { return true; } @Override public abstract JsonToken asToken(); /* NOTE: must have separate implementations since semantics have * slight difference; deprecated method must return null, * new method empty string. */ @SuppressWarnings("deprecation") @Override public String getValueAsText() { return null; } @Override public String asText() { return ""; } /* /********************************************************** /* Find methods; made abstract again to ensure implementation /********************************************************** */ @Override public abstract JsonNode findValue(String fieldName); @Override public abstract ObjectNode findParent(String fieldName); @Override public abstract List findValues(String fieldName, List foundSoFar); @Override public abstract List findParents(String fieldName, List foundSoFar); @Override public abstract List findValuesAsText(String fieldName, List foundSoFar); /* /********************************************************** /* Methods reset as abstract to force real implementation /********************************************************** */ @Override public abstract int size(); @Override public abstract JsonNode get(int index); @Override public abstract JsonNode get(String fieldName); /* /********************************************************** /* NodeCreator implementation, just dispatch to /* the real creator /********************************************************** */ /** * Factory method that constructs and returns an empty {@link ArrayNode} * Construction is done using registered {@link JsonNodeFactory}. */ public final ArrayNode arrayNode() { return _nodeFactory.arrayNode(); } /** * Factory method that constructs and returns an empty {@link ObjectNode} * Construction is done using registered {@link JsonNodeFactory}. */ public final ObjectNode objectNode() { return _nodeFactory.objectNode(); } public final NullNode nullNode() { return _nodeFactory.nullNode(); } public final BooleanNode booleanNode(boolean v) { return _nodeFactory.booleanNode(v); } public final NumericNode numberNode(byte v) { return _nodeFactory.numberNode(v); } public final NumericNode numberNode(short v) { return _nodeFactory.numberNode(v); } public final NumericNode numberNode(int v) { return _nodeFactory.numberNode(v); } public final NumericNode numberNode(long v) { return _nodeFactory.numberNode(v); } public final NumericNode numberNode(float v) { return _nodeFactory.numberNode(v); } public final NumericNode numberNode(double v) { return _nodeFactory.numberNode(v); } public final NumericNode numberNode(BigDecimal v) { return (_nodeFactory.numberNode(v)); } public final TextNode textNode(String text) { return _nodeFactory.textNode(text); } public final BinaryNode binaryNode(byte[] data) { return _nodeFactory.binaryNode(data); } public final BinaryNode binaryNode(byte[] data, int offset, int length) { return _nodeFactory.binaryNode(data, offset, length); } public final POJONode POJONode(Object pojo) { return _nodeFactory.POJONode(pojo); } /* /********************************************************** /* Common mutators /********************************************************** */ /** * Method for removing all children container has (if any) * * @return Container node itself (to allow method call chaining) * * @since 1.3 */ public abstract ContainerNode removeAll(); /* /********************************************************** /* Helper classes /********************************************************** */ protected static class NoNodesIterator implements Iterator { final static NoNodesIterator instance = new NoNodesIterator(); private NoNodesIterator() { } public static NoNodesIterator instance() { return instance; } @Override public boolean hasNext() { return false; } @Override public JsonNode next() { throw new NoSuchElementException(); } @Override public void remove() { // could as well throw IllegalOperationException? throw new IllegalStateException(); } } protected static class NoStringsIterator implements Iterator { final static NoStringsIterator instance = new NoStringsIterator(); private NoStringsIterator() { } public static NoStringsIterator instance() { return instance; } @Override public boolean hasNext() { return false; } @Override public String next() { throw new NoSuchElementException(); } @Override public void remove() { // could as well throw IllegalOperationException? throw new IllegalStateException(); } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/LongNode.java0000644000175000017500000000455411655120726026732 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.io.NumberOutput; import org.codehaus.jackson.map.SerializerProvider; /** * Numeric node that contains simple 64-bit integer values. */ public final class LongNode extends NumericNode { final long _value; /* ************************************************ * Construction ************************************************ */ public LongNode(long v) { _value = v; } public static LongNode valueOf(long l) { return new LongNode(l); } /* ************************************************ * Overrridden JsonNode methods ************************************************ */ @Override public JsonToken asToken() { return JsonToken.VALUE_NUMBER_INT; } @Override public JsonParser.NumberType getNumberType() { return JsonParser.NumberType.LONG; } @Override public boolean isIntegralNumber() { return true; } @Override public boolean isLong() { return true; } @Override public Number getNumberValue() { return Long.valueOf(_value); } @Override public int getIntValue() { return (int) _value; } @Override public long getLongValue() { return _value; } @Override public double getDoubleValue() { return (double) _value; } @Override public BigDecimal getDecimalValue() { return BigDecimal.valueOf(_value); } @Override public BigInteger getBigIntegerValue() { return BigInteger.valueOf(_value); } @Override public String asText() { return NumberOutput.toString(_value); } @Override public boolean asBoolean(boolean defaultValue) { return _value != 0; } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeNumber(_value); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } return ((LongNode) o)._value == _value; } @Override public int hashCode() { return ((int) _value) ^ (int) (_value >> 32); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/NodeCursor.java0000644000175000017500000001374411655120726027311 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.util.*; import org.codehaus.jackson.*; /** * Helper class used by {@link TreeTraversingParser} to keep track * of current location within traversed JSON tree. */ abstract class NodeCursor extends JsonStreamContext { /** * Parent cursor of this cursor, if any; null for root * cursors. */ final NodeCursor _parent; public NodeCursor(int contextType, NodeCursor p) { super(); _type = contextType; _index = -1; _parent = p; } /* /********************************************************** /* JsonStreamContext impl /********************************************************** */ // note: co-variant return type @Override public final NodeCursor getParent() { return _parent; } @Override public abstract String getCurrentName(); /* /********************************************************** /* Extended API /********************************************************** */ public abstract JsonToken nextToken(); public abstract JsonToken nextValue(); public abstract JsonToken endToken(); public abstract JsonNode currentNode(); public abstract boolean currentHasChildren(); /** * Method called to create a new context for iterating all * contents of the current structured value (JSON array or object) */ public final NodeCursor iterateChildren() { JsonNode n = currentNode(); if (n == null) throw new IllegalStateException("No current node"); if (n.isArray()) { // false since we have already returned START_ARRAY return new Array(n, this); } if (n.isObject()) { return new Object(n, this); } throw new IllegalStateException("Current node of type "+n.getClass().getName()); } /* /********************************************************** /* Concrete implementations /********************************************************** */ /** * Context matching root-level value nodes (i.e. anything other * than JSON Object and Array). * Note that context is NOT created for leaf values. */ protected final static class RootValue extends NodeCursor { JsonNode _node; protected boolean _done = false; public RootValue(JsonNode n, NodeCursor p) { super(JsonStreamContext.TYPE_ROOT, p); _node = n; } @Override public String getCurrentName() { return null; } @Override public JsonToken nextToken() { if (!_done) { _done = true; return _node.asToken(); } _node = null; return null; } @Override public JsonToken nextValue() { return nextToken(); } @Override public JsonToken endToken() { return null; } @Override public JsonNode currentNode() { return _node; } @Override public boolean currentHasChildren() { return false; } } /** * Cursor used for traversing non-empty JSON Array nodes */ protected final static class Array extends NodeCursor { Iterator _contents; JsonNode _currentNode; public Array(JsonNode n, NodeCursor p) { super(JsonStreamContext.TYPE_ARRAY, p); _contents = n.getElements(); } @Override public String getCurrentName() { return null; } @Override public JsonToken nextToken() { if (!_contents.hasNext()) { _currentNode = null; return null; } _currentNode = _contents.next(); return _currentNode.asToken(); } @Override public JsonToken nextValue() { return nextToken(); } @Override public JsonToken endToken() { return JsonToken.END_ARRAY; } @Override public JsonNode currentNode() { return _currentNode; } @Override public boolean currentHasChildren() { // note: ONLY to be called for container nodes return ((ContainerNode) currentNode()).size() > 0; } } /** * Cursor used for traversing non-empty JSON Object nodes */ protected final static class Object extends NodeCursor { Iterator> _contents; Map.Entry _current; boolean _needEntry; public Object(JsonNode n, NodeCursor p) { super(JsonStreamContext.TYPE_OBJECT, p); _contents = ((ObjectNode) n).getFields(); _needEntry = true; } @Override public String getCurrentName() { return (_current == null) ? null : _current.getKey(); } @Override public JsonToken nextToken() { // Need a new entry? if (_needEntry) { if (!_contents.hasNext()) { _current = null; return null; } _needEntry = false; _current = _contents.next(); return JsonToken.FIELD_NAME; } _needEntry = true; return _current.getValue().asToken(); } @Override public JsonToken nextValue() { JsonToken t = nextToken(); if (t == JsonToken.FIELD_NAME) { t = nextToken(); } return t; } @Override public JsonToken endToken() { return JsonToken.END_OBJECT; } @Override public JsonNode currentNode() { return (_current == null) ? null : _current.getValue(); } @Override public boolean currentHasChildren() { // note: ONLY to be called for container nodes return ((ContainerNode) currentNode()).size() > 0; } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/ArrayNode.java0000644000175000017500000004627211655120726027114 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.util.*; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.TypeSerializer; /** * Node class that represents Arrays mapped from Json content. */ public final class ArrayNode extends ContainerNode { protected ArrayList _children; public ArrayNode(JsonNodeFactory nc) { super(nc); } /* /********************************************************** /* Implementation of core JsonNode API /********************************************************** */ @Override public JsonToken asToken() { return JsonToken.START_ARRAY; } @Override public boolean isArray() { return true; } @Override public int size() { return (_children == null) ? 0 : _children.size(); } @Override public Iterator getElements() { return (_children == null) ? NoNodesIterator.instance() : _children.iterator(); } @Override public JsonNode get(int index) { if (index >= 0 && (_children != null) && index < _children.size()) { return _children.get(index); } return null; } @Override public JsonNode get(String fieldName) { return null; } @Override public JsonNode path(String fieldName) { return MissingNode.getInstance(); } @Override public JsonNode path(int index) { if (index >= 0 && (_children != null) && index < _children.size()) { return _children.get(index); } return MissingNode.getInstance(); } /* /********************************************************** /* Public API, serialization /********************************************************** */ @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeStartArray(); if (_children != null) { for (JsonNode n : _children) { /* 17-Feb-2009, tatu: Can we trust that all nodes will always * extend BaseJsonNode? Or if not, at least implement * JsonSerializable? Let's start with former, change if * we must. */ ((BaseJsonNode)n).serialize(jg, provider); } } jg.writeEndArray(); } @Override public void serializeWithType(JsonGenerator jg, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { typeSer.writeTypePrefixForArray(this, jg); if (_children != null) { for (JsonNode n : _children) { ((BaseJsonNode)n).serialize(jg, provider); } } typeSer.writeTypeSuffixForArray(this, jg); } /* /********************************************************** /* Public API, finding value nodes /********************************************************** */ @Override public JsonNode findValue(String fieldName) { if (_children != null) { for (JsonNode node : _children) { JsonNode value = node.findValue(fieldName); if (value != null) { return value; } } } return null; } @Override public List findValues(String fieldName, List foundSoFar) { if (_children != null) { for (JsonNode node : _children) { foundSoFar = node.findValues(fieldName, foundSoFar); } } return foundSoFar; } @Override public List findValuesAsText(String fieldName, List foundSoFar) { if (_children != null) { for (JsonNode node : _children) { foundSoFar = node.findValuesAsText(fieldName, foundSoFar); } } return foundSoFar; } @Override public ObjectNode findParent(String fieldName) { if (_children != null) { for (JsonNode node : _children) { JsonNode parent = node.findParent(fieldName); if (parent != null) { return (ObjectNode) parent; } } } return null; } @Override public List findParents(String fieldName, List foundSoFar) { if (_children != null) { for (JsonNode node : _children) { foundSoFar = node.findParents(fieldName, foundSoFar); } } return foundSoFar; } /* /********************************************************** /* Extended ObjectNode API, accessors /********************************************************** */ /** * Method that will set specified field, replacing old value, * if any. * * @param value to set field to; if null, will be converted * to a {@link NullNode} first (to remove field entry, call * {@link #remove} instead) * * @return Old value of the field, if any; null if there was no * old value. */ public JsonNode set(int index, JsonNode value) { if (value == null) { // let's not store 'raw' nulls but nodes value = nullNode(); } return _set(index, value); } public void add(JsonNode value) { if (value == null) { // let's not store 'raw' nulls but nodes value = nullNode(); } _add(value); } /** * Method for adding all child nodes of given Array, appending to * child nodes this array contains * * @param other Array to add contents from * * @return This node (to allow chaining) * * @since 1.3 */ public JsonNode addAll(ArrayNode other) { int len = other.size(); if (len > 0) { if (_children == null) { _children = new ArrayList(len+2); } other.addContentsTo(_children); } return this; } /** * Method for adding given nodes as child nodes of this array node. * * @param nodes Nodes to add * * @return This node (to allow chaining) * * @since 1.3 */ public JsonNode addAll(Collection nodes) { int len = nodes.size(); if (len > 0) { if (_children == null) { _children = new ArrayList(nodes); } else { _children.addAll(nodes); } } return this; } /** * Method for inserting specified child node as an element * of this Array. If index is 0 or less, it will be inserted as * the first element; if >= size(), appended at the end, and otherwise * inserted before existing element in specified index. * No exceptions are thrown for any index. */ public void insert(int index, JsonNode value) { if (value == null) { value = nullNode(); } _insert(index, value); } /** * Method for removing an entry from this ArrayNode. * Will return value of the entry at specified index, if entry existed; * null if not. */ public JsonNode remove(int index) { if (index >= 0 && (_children != null) && index < _children.size()) { return _children.remove(index); } return null; } @Override public ArrayNode removeAll() { _children = null; return this; } /* /********************************************************** /* Extended ObjectNode API, mutators, generic; addXxx()/insertXxx() /********************************************************** */ /** * Method that will construct an ArrayNode and add it as a * field of this ObjectNode, replacing old value, if any. * * @return Newly constructed ArrayNode */ public ArrayNode addArray() { ArrayNode n = arrayNode(); _add(n); return n; } /** * Method that will construct an ObjectNode and add it at the end * of this array node. * * @return Newly constructed ObjectNode */ public ObjectNode addObject() { ObjectNode n = objectNode(); _add(n); return n; } /** * Method that will construct a POJONode and add it at the end * of this array node. */ public void addPOJO(Object value) { if (value == null) { addNull(); } else { _add(POJONode(value)); } } public void addNull() { _add(nullNode()); } /** * Method for setting value of a field to specified numeric value. */ public void add(int v) { _add(numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void add(Integer value) { if (value == null) { addNull(); } else { _add(numberNode(value.intValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void add(long v) { _add(numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void add(Long value) { if (value == null) { addNull(); } else { _add(numberNode(value.longValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void add(float v) { _add(numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void add(Float value) { if (value == null) { addNull(); } else { _add(numberNode(value.floatValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void add(double v) { _add(numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void add(Double value) { if (value == null) { addNull(); } else { _add(numberNode(value.doubleValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void add(BigDecimal v) { if (v == null) { addNull(); } else { _add(numberNode(v)); } } /** * Method for setting value of a field to specified String value. */ public void add(String v) { if (v == null) { addNull(); } else { _add(textNode(v)); } } /** * Method for setting value of a field to specified String value. */ public void add(boolean v) { _add(booleanNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void add(Boolean value) { if (value == null) { addNull(); } else { _add(booleanNode(value.booleanValue())); } } /** * Method for setting value of a field to specified binary value */ public void add(byte[] v) { if (v == null) { addNull(); } else { _add(binaryNode(v)); } } public ArrayNode insertArray(int index) { ArrayNode n = arrayNode(); _insert(index, n); return n; } /** * Method that will construct an ObjectNode and add it at the end * of this array node. * * @return Newly constructed ObjectNode */ public ObjectNode insertObject(int index) { ObjectNode n = objectNode(); _insert(index, n); return n; } /** * Method that will construct a POJONode and add it at the end * of this array node. */ public void insertPOJO(int index, Object value) { if (value == null) { insertNull(index); } else { _insert(index, POJONode(value)); } } public void insertNull(int index) { _insert(index, nullNode()); } /** * Method for setting value of a field to specified numeric value. */ public void insert(int index, int v) { _insert(index, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void insert(int index, Integer value) { if (value == null) { insertNull(index); } else { _insert(index, numberNode(value.intValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void insert(int index, long v) { _insert(index, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void insert(int index, Long value) { if (value == null) { insertNull(index); } else { _insert(index, numberNode(value.longValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void insert(int index, float v) { _insert(index, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void insert(int index, Float value) { if (value == null) { insertNull(index); } else { _insert(index, numberNode(value.floatValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void insert(int index, double v) { _insert(index, numberNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void insert(int index, Double value) { if (value == null) { insertNull(index); } else { _insert(index, numberNode(value.doubleValue())); } } /** * Method for setting value of a field to specified numeric value. */ public void insert(int index, BigDecimal v) { if (v == null) { insertNull(index); } else { _insert(index, numberNode(v)); } } /** * Method for setting value of a field to specified String value. */ public void insert(int index, String v) { if (v == null) { insertNull(index); } else { _insert(index, textNode(v)); } } /** * Method for setting value of a field to specified String value. */ public void insert(int index, boolean v) { _insert(index, booleanNode(v)); } /** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @since 1.9 */ public void insert(int index, Boolean value) { if (value == null) { insertNull(index); } else { _insert(index, booleanNode(value.booleanValue())); } } /** * Method for setting value of a field to specified binary value */ public void insert(int index, byte[] v) { if (v == null) { insertNull(index); } else { _insert(index, binaryNode(v)); } } /* /********************************************************** /* Package methods (for other node classes to use) /********************************************************** */ /** * @since 1.6 */ protected void addContentsTo(List dst) { if (_children != null) { for (JsonNode n : _children) { dst.add(n); } } } /* /********************************************************** /* Standard methods /********************************************************** */ @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } ArrayNode other = (ArrayNode) o; if (_children == null || _children.size() == 0) { return other.size() == 0; } return other._sameChildren(_children); } @Override public int hashCode() { int hash; if (_children == null) { hash = 1; } else { hash = _children.size(); for (JsonNode n : _children) { if (n != null) { hash ^= n.hashCode(); } } } return hash; } @Override public String toString() { StringBuilder sb = new StringBuilder(16 + (size() << 4)); sb.append('['); if (_children != null) { for (int i = 0, len = _children.size(); i < len; ++i) { if (i > 0) { sb.append(','); } sb.append(_children.get(i).toString()); } } sb.append(']'); return sb.toString(); } /* /********************************************************** /* Internal methods /********************************************************** */ public JsonNode _set(int index, JsonNode value) { if (_children == null || index < 0 || index >= _children.size()) { throw new IndexOutOfBoundsException("Illegal index "+index+", array size "+size()); } return _children.set(index, value); } private void _add(JsonNode node) { if (_children == null) { _children = new ArrayList(); } _children.add(node); } private void _insert(int index, JsonNode node) { if (_children == null) { _children = new ArrayList(); _children.add(node); return; } if (index < 0) { _children.add(0, node); } else if (index >= _children.size()) { _children.add(node); } else { _children.add(index, node); } } /** * Note: this method gets called iff otherChildren * is non-empty */ private boolean _sameChildren(ArrayList otherChildren) { int len = otherChildren.size(); if (this.size() != len) { // important: call size() to handle case of null list... return false; } for (int i = 0; i < len; ++i) { if (!_children.get(i).equals(otherChildren.get(i))) { return false; } } return true; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/TreeTraversingParser.java0000644000175000017500000002530611655120726031344 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.impl.JsonParserMinimalBase; /** * Facade over {@link JsonNode} that implements {@link JsonParser} to allow * accessing contents of JSON tree in alternate form (stream of tokens). * Useful when a streaming source is expected by code, such as data binding * functionality. * * @author tatu * * @since 1.3 */ public class TreeTraversingParser extends JsonParserMinimalBase { /* /********************************************************** /* Configuration /********************************************************** */ protected ObjectCodec _objectCodec; /** * Traversal context within tree */ protected NodeCursor _nodeCursor; /* /********************************************************** /* State /********************************************************** */ /** * Sometimes parser needs to buffer a single look-ahead token; if so, * it'll be stored here. This is currently used for handling */ protected JsonToken _nextToken; /** * Flag needed to handle recursion into contents of child * Array/Object nodes. */ protected boolean _startContainer; /** * Flag that indicates whether parser is closed or not. Gets * set when parser is either closed by explicit call * ({@link #close}) or when end-of-input is reached. */ protected boolean _closed; /* /********************************************************** /* Life-cycle /********************************************************** */ public TreeTraversingParser(JsonNode n) { this(n, null); } public TreeTraversingParser(JsonNode n, ObjectCodec codec) { super(0); _objectCodec = codec; if (n.isArray()) { _nextToken = JsonToken.START_ARRAY; _nodeCursor = new NodeCursor.Array(n, null); } else if (n.isObject()) { _nextToken = JsonToken.START_OBJECT; _nodeCursor = new NodeCursor.Object(n, null); } else { // value node _nodeCursor = new NodeCursor.RootValue(n, null); } } @Override public void setCodec(ObjectCodec c) { _objectCodec = c; } @Override public ObjectCodec getCodec() { return _objectCodec; } /* /********************************************************** /* Closeable implementation /********************************************************** */ @Override public void close() throws IOException { if (!_closed) { _closed = true; _nodeCursor = null; _currToken = null; } } /* /********************************************************** /* Public API, traversal /********************************************************** */ @Override public JsonToken nextToken() throws IOException, JsonParseException { if (_nextToken != null) { _currToken = _nextToken; _nextToken = null; return _currToken; } // are we to descend to a container child? if (_startContainer) { _startContainer = false; // minor optimization: empty containers can be skipped if (!_nodeCursor.currentHasChildren()) { _currToken = (_currToken == JsonToken.START_OBJECT) ? JsonToken.END_OBJECT : JsonToken.END_ARRAY; return _currToken; } _nodeCursor = _nodeCursor.iterateChildren(); _currToken = _nodeCursor.nextToken(); if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { _startContainer = true; } return _currToken; } // No more content? if (_nodeCursor == null) { _closed = true; // if not already set return null; } // Otherwise, next entry from current cursor _currToken = _nodeCursor.nextToken(); if (_currToken != null) { if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { _startContainer = true; } return _currToken; } // null means no more children; need to return end marker _currToken = _nodeCursor.endToken(); _nodeCursor = _nodeCursor.getParent(); return _currToken; } // default works well here: //public JsonToken nextValue() throws IOException, JsonParseException @Override public JsonParser skipChildren() throws IOException, JsonParseException { if (_currToken == JsonToken.START_OBJECT) { _startContainer = false; _currToken = JsonToken.END_OBJECT; } else if (_currToken == JsonToken.START_ARRAY) { _startContainer = false; _currToken = JsonToken.END_ARRAY; } return this; } @Override public boolean isClosed() { return _closed; } /* /********************************************************** /* Public API, token accessors /********************************************************** */ @Override public String getCurrentName() { return (_nodeCursor == null) ? null : _nodeCursor.getCurrentName(); } @Override public JsonStreamContext getParsingContext() { return _nodeCursor; } @Override public JsonLocation getTokenLocation() { return JsonLocation.NA; } @Override public JsonLocation getCurrentLocation() { return JsonLocation.NA; } /* /********************************************************** /* Public API, access to textual content /********************************************************** */ @Override public String getText() { if (_closed) { return null; } // need to separate handling a bit... switch (_currToken) { case FIELD_NAME: return _nodeCursor.getCurrentName(); case VALUE_STRING: return currentNode().getTextValue(); case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: return String.valueOf(currentNode().getNumberValue()); case VALUE_EMBEDDED_OBJECT: JsonNode n = currentNode(); if (n != null && n.isBinary()) { // this will convert it to base64 return n.asText(); } } return (_currToken == null) ? null : _currToken.asString(); } @Override public char[] getTextCharacters() throws IOException, JsonParseException { return getText().toCharArray(); } @Override public int getTextLength() throws IOException, JsonParseException { return getText().length(); } @Override public int getTextOffset() throws IOException, JsonParseException { return 0; } @Override public boolean hasTextCharacters() { // generally we do not have efficient access as char[], hence: return false; } /* /********************************************************** /* Public API, typed non-text access /********************************************************** */ //public byte getByteValue() throws IOException, JsonParseException @Override public NumberType getNumberType() throws IOException, JsonParseException { JsonNode n = currentNumericNode(); return (n == null) ? null : n.getNumberType(); } @Override public BigInteger getBigIntegerValue() throws IOException, JsonParseException { return currentNumericNode().getBigIntegerValue(); } @Override public BigDecimal getDecimalValue() throws IOException, JsonParseException { return currentNumericNode().getDecimalValue(); } @Override public double getDoubleValue() throws IOException, JsonParseException { return currentNumericNode().getDoubleValue(); } @Override public float getFloatValue() throws IOException, JsonParseException { return (float) currentNumericNode().getDoubleValue(); } @Override public long getLongValue() throws IOException, JsonParseException { return currentNumericNode().getLongValue(); } @Override public int getIntValue() throws IOException, JsonParseException { return currentNumericNode().getIntValue(); } @Override public Number getNumberValue() throws IOException, JsonParseException { return currentNumericNode().getNumberValue(); } @Override public Object getEmbeddedObject() { if (!_closed) { JsonNode n = currentNode(); if (n != null && n.isPojo()) { return ((POJONode) n).getPojo(); } } return null; } /* /********************************************************** /* Public API, typed binary (base64) access /********************************************************** */ @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException { // Multiple possibilities... JsonNode n = currentNode(); if (n != null) { // binary node? byte[] data = n.getBinaryValue(); // (or TextNode, which can also convert automatically!) if (data != null) { return data; } // Or maybe byte[] as POJO? if (n.isPojo()) { Object ob = ((POJONode) n).getPojo(); if (ob instanceof byte[]) { return (byte[]) ob; } } } // otherwise return null to mark we have no binary content return null; } /* /********************************************************** /* Internal methods /********************************************************** */ protected JsonNode currentNode() { if (_closed || _nodeCursor == null) { return null; } return _nodeCursor.currentNode(); } protected JsonNode currentNumericNode() throws JsonParseException { JsonNode n = currentNode(); if (n == null || !n.isNumber()) { JsonToken t = (n == null) ? null : n.asToken(); throw _constructError("Current token ("+t+") not numeric, can not use numeric value accessors"); } return n; } @Override protected void _handleEOF() throws JsonParseException { _throwInternal(); // should never get called } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/package-info.java0000644000175000017500000000050711655120726027543 0ustar jamespagejamespage/** * Contains concrete {@link org.codehaus.jackson.JsonNode} implementations * Jackson uses for the Tree model. * These classes are public since concrete type will be needed * for most operations that modify node trees. For read-only access concrete * types are usually not needed. */ package org.codehaus.jackson.node; jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/DoubleNode.java0000644000175000017500000000527211655120726027243 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.io.NumberOutput; import org.codehaus.jackson.map.SerializerProvider; /** * Numeric node that contains 64-bit ("double precision") * floating point values simple 32-bit integer values. */ public final class DoubleNode extends NumericNode { protected final double _value; /* /********************************************************** /* Construction /********************************************************** */ public DoubleNode(double v) { _value = v; } public static DoubleNode valueOf(double v) { return new DoubleNode(v); } /* /********************************************************** /* BaseJsonNode extended API /********************************************************** */ @Override public JsonToken asToken() { return JsonToken.VALUE_NUMBER_FLOAT; } @Override public JsonParser.NumberType getNumberType() { return JsonParser.NumberType.DOUBLE; } /* /********************************************************** /* Overrridden JsonNode methods /********************************************************** */ @Override public boolean isFloatingPointNumber() { return true; } @Override public boolean isDouble() { return true; } @Override public Number getNumberValue() { return Double.valueOf(_value); } @Override public int getIntValue() { return (int) _value; } @Override public long getLongValue() { return (long) _value; } @Override public double getDoubleValue() { return _value; } @Override public BigDecimal getDecimalValue() { return BigDecimal.valueOf(_value); } @Override public BigInteger getBigIntegerValue() { return getDecimalValue().toBigInteger(); } @Override public String asText() { return NumberOutput.toString(_value); } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeNumber(_value); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } return ((DoubleNode) o)._value == _value; } @Override public int hashCode() { // same as hashCode Double.class uses long l = Double.doubleToLongBits(_value); return ((int) l) ^ (int) (l >> 32); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/POJONode.java0000644000175000017500000000653711655120726026605 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; /** * Value node that contains a wrapped POJO, to be serialized as * a JSON constructed through data mapping (usually done by * calling {@link org.codehaus.jackson.map.ObjectMapper}). */ public final class POJONode extends ValueNode { protected final Object _value; public POJONode(Object v) { _value = v; } /* /********************************************************** /* Base class overrides /********************************************************** */ @Override public JsonToken asToken() { return JsonToken.VALUE_EMBEDDED_OBJECT; } @Override public boolean isPojo() { return true; } /* /********************************************************** /* General type coercions /********************************************************** */ @Override public String asText() { return (_value == null) ? "null" : _value.toString(); } @Override public boolean asBoolean(boolean defaultValue) { if (_value != null && _value instanceof Boolean) { return ((Boolean) _value).booleanValue(); } return defaultValue; } @Override public int asInt(int defaultValue) { if (_value instanceof Number) { return ((Number) _value).intValue(); } return defaultValue; } @Override public long asLong(long defaultValue) { if (_value instanceof Number) { return ((Number) _value).longValue(); } return defaultValue; } @Override public double asDouble(double defaultValue) { if (_value instanceof Number) { return ((Number) _value).doubleValue(); } return defaultValue; } /* /********************************************************** /* Public API, serialization /********************************************************** */ @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { if (_value == null) { jg.writeNull(); } else { jg.writeObject(_value); } } /* /********************************************************** /* Extended API /********************************************************** */ /** * Method that can be used to access the POJO this node wraps. */ public Object getPojo() { return _value; } /* /********************************************************** /* Overridden standard methods /********************************************************** */ @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } POJONode other = (POJONode) o; if (_value == null) { return other._value == null; } return _value.equals(other._value); } @Override public int hashCode() { return _value.hashCode(); } @Override public String toString() { return String.valueOf(_value); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/MissingNode.java0000644000175000017500000000531711655120726027442 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.TypeSerializer; /** * This singleton node class is generated to denote "missing nodes" * along paths that do not exist. For example, if a path via * element of an array is requested for an element outside range * of elements in the array; or for a non-array value, result * will be reference to this node. *

* In most respects this placeholder node will act as {@link NullNode}; * for example, for purposes of value conversions, value is considered * to be null and represented as value zero when used for numeric * conversions. */ public final class MissingNode extends BaseJsonNode { private final static MissingNode instance = new MissingNode(); private MissingNode() { } public static MissingNode getInstance() { return instance; } @Override public JsonToken asToken() { return JsonToken.NOT_AVAILABLE; } @Override public boolean isMissingNode() { return true; } @Override public String asText() { return null; } @Override public int asInt(int defaultValue) { return 0; } @Override public long asLong(long defaultValue) { return 0L; } @Override public double asDouble(double defaultValue) { return 0.0; } @Override public JsonNode path(String fieldName) { return this; } @Override public JsonNode path(int index) { return this; } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { /* Nothing to output... should we signal an error tho? * Chances are, this is an erroneous call. For now, let's * not do that. */ jg.writeNull(); } @Override public void serializeWithType(JsonGenerator jg, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { jg.writeNull(); } @Override public boolean equals(Object o) { /* Hmmh. Since there's just a singleton instance, this * fails in all cases but with identity comparison. * However: if this placeholder value was to be considered * similar to Sql NULL, it shouldn't even equal itself? * That might cause problems when dealing with collections * like Sets... so for now, let's let identity comparison * return true. */ return (o == this); } @Override public String toString() { // toString() should never return null return ""; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/DecimalNode.java0000644000175000017500000000476711655120726027377 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; /** * Numeric node that contains values that do not fit in simple * integer (int, long) or floating point (double) values. */ public final class DecimalNode extends NumericNode { final protected BigDecimal _value; /* /********************************************************** /* Construction /********************************************************** */ public DecimalNode(BigDecimal v) { _value = v; } public static DecimalNode valueOf(BigDecimal d) { return new DecimalNode(d); } /* /********************************************************** /* BaseJsonNode extended API /********************************************************** */ @Override public JsonToken asToken() { return JsonToken.VALUE_NUMBER_FLOAT; } @Override public JsonParser.NumberType getNumberType() { return JsonParser.NumberType.BIG_DECIMAL; } /* /********************************************************** /* Overrridden JsonNode methods /********************************************************** */ @Override public boolean isFloatingPointNumber() { return true; } @Override public boolean isBigDecimal() { return true; } @Override public Number getNumberValue() { return _value; } @Override public int getIntValue() { return _value.intValue(); } @Override public long getLongValue() { return _value.longValue(); } @Override public BigInteger getBigIntegerValue() { return _value.toBigInteger(); } @Override public double getDoubleValue() { return _value.doubleValue(); } @Override public BigDecimal getDecimalValue() { return _value; } @Override public String asText() { return _value.toString(); } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeNumber(_value); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } return ((DecimalNode) o)._value.equals(_value); } @Override public int hashCode() { return _value.hashCode(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/BinaryNode.java0000644000175000017500000000563511655120726027260 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.util.Arrays; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; /** * Value node that contains Base64 encoded binary value, which will be * output and stored as Json String value. */ public final class BinaryNode extends ValueNode { final static BinaryNode EMPTY_BINARY_NODE = new BinaryNode(new byte[0]); final byte[] _data; public BinaryNode(byte[] data) { _data = data; } public BinaryNode(byte[] data, int offset, int length) { if (offset == 0 && length == data.length) { _data = data; } else { _data = new byte[length]; System.arraycopy(data, offset, _data, 0, length); } } public static BinaryNode valueOf(byte[] data) { if (data == null) { return null; } if (data.length == 0) { return EMPTY_BINARY_NODE; } return new BinaryNode(data); } public static BinaryNode valueOf(byte[] data, int offset, int length) { if (data == null) { return null; } if (length == 0) { return EMPTY_BINARY_NODE; } return new BinaryNode(data, offset, length); } @Override public JsonToken asToken() { /* No distinct type; could use one for textual values, * but given that it's not in text form at this point, * embedded-object is closest */ return JsonToken.VALUE_EMBEDDED_OBJECT; } @Override public boolean isBinary() { return true; } /** *

* Note: caller is not to modify returned array in any way, since * it is not a copy but reference to the underlying byte array. */ @Override public byte[] getBinaryValue() { return _data; } /** * Hmmh. This is not quite as efficient as using {@link #serialize}, * but will work correctly. */ @Override public String asText() { return Base64Variants.getDefaultVariant().encode(_data, false); } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeBinary(_data); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } return Arrays.equals(((BinaryNode) o)._data, _data); } @Override public int hashCode() { return (_data == null) ? -1 : _data.length; } /** * Different from other values, since contents need to be surrounded * by (double) quotes. */ @Override public String toString() { return Base64Variants.getDefaultVariant().encode(_data, true); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/ValueNode.java0000644000175000017500000000324711655120726027105 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.TypeSerializer; /** * This intermediate base class is used for all leaf nodes, that is, * all non-container (array or object) nodes, except for the * "missing node". */ public abstract class ValueNode extends BaseJsonNode { protected ValueNode() { } @Override public boolean isValueNode() { return true; } @Override public abstract JsonToken asToken(); @Override public void serializeWithType(JsonGenerator jg, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { typeSer.writeTypePrefixForScalar(this, jg); serialize(jg, provider); typeSer.writeTypeSuffixForScalar(this, jg); } /* /********************************************************************** /* Public API, path handling /********************************************************************** */ @Override public JsonNode path(String fieldName) { return MissingNode.getInstance(); } @Override public JsonNode path(int index) { return MissingNode.getInstance(); } /* /********************************************************************** /* Base impls for standard methods /********************************************************************** */ @Override public String toString() { return asText(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/BaseJsonNode.java0000644000175000017500000000652511655120726027537 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.util.List; import org.codehaus.jackson.*; import org.codehaus.jackson.map.JsonSerializableWithType; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.TypeSerializer; /** * Abstract base class common to all standard {@link JsonNode} * implementations. * The main addition here is that we declare that sub-classes must * implement {@link JsonSerializableWithType}. * This simplifies object mapping * aspects a bit, as no external serializers are needed. */ public abstract class BaseJsonNode extends JsonNode implements JsonSerializableWithType { protected BaseJsonNode() { } /* /********************************************************** /* Basic definitions for non-container types /********************************************************** */ @Override public JsonNode findValue(String fieldName) { return null; } @Override public final JsonNode findPath(String fieldName) { JsonNode value = findValue(fieldName); if (value == null) { return MissingNode.getInstance(); } return value; } // note: co-variant return type @Override public ObjectNode findParent(String fieldName) { return null; } @Override public List findValues(String fieldName, List foundSoFar) { return foundSoFar; } @Override public List findValuesAsText(String fieldName, List foundSoFar) { return foundSoFar; } @Override public List findParents(String fieldName, List foundSoFar) { return foundSoFar; } /* /********************************************************** /* Support for traversal-as-stream /********************************************************** */ @Override public JsonParser traverse() { return new TreeTraversingParser(this); } /** * Method that can be used for efficient type detection * when using stream abstraction for traversing nodes. * Will return the first {@link JsonToken} that equivalent * stream event would produce (for most nodes there is just * one token but for structured/container types multiple) * * @since 1.3 */ @Override public abstract JsonToken asToken(); /** * @since 1.3 */ @Override public JsonParser.NumberType getNumberType() { // most types non-numeric, so: return null; } /* /********************************************************** /* JsonSerializable /********************************************************** */ /** * Method called to serialize node instances using given generator. */ @SuppressWarnings("deprecation") @Override public abstract void serialize(JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException; /** * Type information is needed, even if JsonNode instances are "plain" JSON, * since they may be mixed with other types. */ @Override public abstract void serializeWithType(JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/node/BigIntegerNode.java0000644000175000017500000000511711655120726030046 0ustar jamespagejamespagepackage org.codehaus.jackson.node; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import org.codehaus.jackson.*; import org.codehaus.jackson.map.SerializerProvider; /** * Numeric node that contains simple 64-bit integer values. */ public final class BigIntegerNode extends NumericNode { final protected BigInteger _value; /* /********************************************************** /* Construction /********************************************************** */ public BigIntegerNode(BigInteger v) { _value = v; } public static BigIntegerNode valueOf(BigInteger v) { return new BigIntegerNode(v); } /* /********************************************************** /* Overrridden JsonNode methods /********************************************************** */ @Override public JsonToken asToken() { return JsonToken.VALUE_NUMBER_INT; } @Override public JsonParser.NumberType getNumberType() { return JsonParser.NumberType.BIG_INTEGER; } @Override public boolean isIntegralNumber() { return true; } @Override public boolean isBigInteger() { return true; } @Override public Number getNumberValue() { return _value; } @Override public int getIntValue() { return _value.intValue(); } @Override public long getLongValue() { return _value.longValue(); } @Override public BigInteger getBigIntegerValue() { return _value; } @Override public double getDoubleValue() { return _value.doubleValue(); } @Override public BigDecimal getDecimalValue() { return new BigDecimal(_value); } /* /********************************************************** /* General type coercions /********************************************************** */ @Override public String asText() { return _value.toString(); } @Override public boolean asBoolean(boolean defaultValue) { return !BigInteger.ZERO.equals(_value); } @Override public final void serialize(JsonGenerator jg, SerializerProvider provider) throws IOException, JsonProcessingException { jg.writeNumber(_value); } @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) { // final class, can do this return false; } return ((BigIntegerNode) o)._value == _value; } @Override public int hashCode() { return _value.hashCode(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/0000755000175000017500000000000011672662540024206 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ResolvableSerializer.java0000644000175000017500000000161511655120726031200 0ustar jamespagejamespagepackage org.codehaus.jackson.map; /** * Interface used to indicate serializers that want to do post-processing * after construction and being added to {@link SerializerProvider}, * but before being used. This is typically used to resolve references * to other contained types; for example, bean serializers use this * to eagerly find serializers for contained field types. */ public interface ResolvableSerializer { /** * Method called after {@link SerializerProvider} has registered * the serializer, but before it has returned it to the caller. * Called object can then resolve its dependencies to other types, * including self-references (direct or indirect). * * @param provider Provider that has constructed serializer this method * is called on. */ public abstract void resolve(SerializerProvider provider) throws JsonMappingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/AnnotationIntrospector.java0000644000175000017500000015242311655120726031602 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.lang.annotation.Annotation; import java.util.*; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.map.JsonDeserializer; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.deser.ValueInstantiator; import org.codehaus.jackson.map.introspect.*; import org.codehaus.jackson.map.jsontype.NamedType; import org.codehaus.jackson.map.jsontype.TypeResolverBuilder; /** * Abstract class that defines API used for introspecting annotation-based * configuration for serialization and deserialization. Separated * so that different sets of annotations can be supported, and support * plugged-in dynamically. *

* NOTE: due to rapid addition of new methods (and changes to existing methods), * it is strongly recommended that custom implementations should not directly * extend this class, but rather extend {@link NopAnnotationIntrospector}. * This way added methods will not break backwards compatibility of custom annotation * introspectors. */ public abstract class AnnotationIntrospector { /* /********************************************************** /* Helper types /********************************************************** */ /** * Value type used with managed and back references; contains type and * logic name, used to link related references * * @since 1.6 */ public static class ReferenceProperty { public enum Type { /** * Reference property that Jackson manages and that is serialized normally (by serializing * reference object), but is used for resolving back references during * deserialization. * Usually this can be defined by using * {@link org.codehaus.jackson.annotate.JsonManagedReference} */ MANAGED_REFERENCE /** * Reference property that Jackson manages by suppressing it during serialization, * and reconstructing during deserialization. * Usually this can be defined by using * {@link org.codehaus.jackson.annotate.JsonBackReference} */ ,BACK_REFERENCE ; } private final Type _type; private final String _name; public ReferenceProperty(Type t, String n) { _type = t; _name = n; } public static ReferenceProperty managed(String name) { return new ReferenceProperty(Type.MANAGED_REFERENCE, name); } public static ReferenceProperty back(String name) { return new ReferenceProperty(Type.BACK_REFERENCE, name); } public Type getType() { return _type; } public String getName() { return _name; } public boolean isManagedReference() { return _type == Type.MANAGED_REFERENCE; } public boolean isBackReference() { return _type == Type.BACK_REFERENCE; } } /* /********************************************************** /* Factory methods /********************************************************** */ /** * Factory method for accessing "no operation" implementation * of introspector: instance that will never find any annotation-based * configuration. * * @since 1.3 */ public static AnnotationIntrospector nopInstance() { return NopAnnotationIntrospector.instance; } public static AnnotationIntrospector pair(AnnotationIntrospector a1, AnnotationIntrospector a2) { return new Pair(a1, a2); } /* /********************************************************** /* Access to possibly chained introspectors (1.7) /********************************************************** */ /** * Method that can be used to collect all "real" introspectors that * this introspector contains, if any; or this introspector * if it is not a container. Used to get access to all container * introspectors in their priority order. *

* Default implementation returns a Singleton list with this introspector * as contents. * This usually works for sub-classes, except for proxy or delegating "container * introspectors" which need to override implementation. */ public Collection allIntrospectors() { return Collections.singletonList(this); } /** * Method that can be used to collect all "real" introspectors that * this introspector contains, if any; or this introspector * if it is not a container. Used to get access to all container * introspectors in their priority order. *

* Default implementation adds this introspector in result; this usually * works for sub-classes, except for proxy or delegating "container * introspectors" which need to override implementation. */ public Collection allIntrospectors(Collection result) { result.add(this); return result; } /* /********************************************************** /* Generic annotation properties, lookup /********************************************************** */ /** * Method called by framework to determine whether given annotation * is handled by this introspector. */ public abstract boolean isHandled(Annotation ann); /* /********************************************************** /* General class annotations /********************************************************** */ /** * Method that checks whether specified class has annotations * that indicate that it is (or is not) cachable. Exact * semantics depend on type of class annotated and using * class (factory or provider). *

* Currently only used * with deserializers, to determine whether provider * should cache instances, and if no annotations are found, * assumes non-cachable instances. * * @return True, if class is considered cachable within context, * False if not, and null if introspector does not care either * way. */ public Boolean findCachability(AnnotatedClass ac) { return null; } /** * Method for locating name used as "root name" (for use by * some serializers when outputting root-level object -- mostly * for XML compatibility purposes) for given class, if one * is defined. Returns null if no declaration found; can return * explicit empty String, which is usually ignored as well as null. * * @since 1.3 */ public abstract String findRootName(AnnotatedClass ac); /** * Method for finding list of properties to ignore for given class * (null is returned if not specified). * List of property names is applied * after other detection mechanisms, to filter out these specific * properties from being serialized and deserialized. * * @since 1.4 */ public abstract String[] findPropertiesToIgnore(AnnotatedClass ac); /** * Method for checking whether an annotation indicates that all unknown properties * * @since 1.4 */ public abstract Boolean findIgnoreUnknownProperties(AnnotatedClass ac); /** * Method for checking whether properties that have specified type * (class, not generics aware) should be completely ignored for * serialization and deserialization purposes. * * @param ac Type to check * * @return Boolean.TRUE if properties of type should be ignored; * Boolean.FALSE if they are not to be ignored, null for default * handling (which is 'do not ignore') * * @since 1.7 */ public Boolean isIgnorableType(AnnotatedClass ac) { return null; } /** * Method for finding if annotated class has associated filter; and if so, * to return id that is used to locate filter. * * @return Id of the filter to use for filtering properties of annotated * class, if any; or null if none found. */ public Object findFilterId(AnnotatedClass ac) { return null; } /* /********************************************************** /* Property auto-detection /********************************************************** */ /** * Method for checking if annotations indicate changes to minimum visibility levels * needed for auto-detecting property elements (fields, methods, constructors). * A baseline checker is given, and introspector is to either return it as is (if * no annotations are found), or build and return a derived instance (using checker's build * methods). * * @since 1.5 */ public VisibilityChecker findAutoDetectVisibility(AnnotatedClass ac, VisibilityChecker checker) { return checker; } /* /********************************************************** /* Class annotations for Polymorphic type handling (1.5+) /********************************************************** */ /** * Method for checking if given class has annotations that indicate * that specific type resolver is to be used for handling instances. * This includes not only * instantiating resolver builder, but also configuring it based on * relevant annotations (not including ones checked with a call to * {@link #findSubtypes} * * @param config Configuration settings in effect (for serialization or deserialization) * @param ac Annotated class to check for annotations * @param baseType Base java type of value for which resolver is to be found * * @return Type resolver builder for given type, if one found; null if none * * @since 1.5 -- although changed in 1.8 to pass configuration object */ public TypeResolverBuilder findTypeResolver(MapperConfig config, AnnotatedClass ac, JavaType baseType) { return null; } /** * Method for checking if given property entity (field or method) has annotations * that indicate that specific type resolver is to be used for handling instances. * This includes not only * instantiating resolver builder, but also configuring it based on * relevant annotations (not including ones checked with a call to * {@link #findSubtypes} * * @param config Configuration settings in effect (for serialization or deserialization) * @param am Annotated member (field or method) to check for annotations * @param baseType Base java type of property for which resolver is to be found * * @return Type resolver builder for properties of given entity, if one found; * null if none * * @since 1.5 -- although changed in 1.8 to pass configuration object */ public TypeResolverBuilder findPropertyTypeResolver(MapperConfig config, AnnotatedMember am, JavaType baseType) { return null; } /** * Method for checking if given structured property entity (field or method that * has nominal value of Map, Collection or array type) has annotations * that indicate that specific type resolver is to be used for handling type * information of contained values. * This includes not only * instantiating resolver builder, but also configuring it based on * relevant annotations (not including ones checked with a call to * {@link #findSubtypes} * * @param config Configuration settings in effect (for serialization or deserialization) * @param am Annotated member (field or method) to check for annotations * @param containerType Type of property for which resolver is to be found (must be a container type) * * @return Type resolver builder for values contained in properties of given entity, * if one found; null if none * * @since 1.5 -- although changed in 1.8 to pass configuration object */ public TypeResolverBuilder findPropertyContentTypeResolver(MapperConfig config, AnnotatedMember am, JavaType containerType) { return null; } /** * Method for locating annotation-specified subtypes related to annotated * entity (class, method, field). Note that this is only guaranteed to be * a list of directly * declared subtypes, no recursive processing is guarantees (i.e. caller * has to do it if/as necessary) * * @param a Annotated entity (class, field/method) to check for annotations * * @since 1.5 */ public List findSubtypes(Annotated a) { return null; } /** * Method for checking if specified type has explicit name. * * @param ac Class to check for type name annotations * * @since 1.5 */ public String findTypeName(AnnotatedClass ac) { return null; } /* /********************************************************** /* General member (field, method/constructor) annotations /********************************************************** */ /** * Note: defined as non-abstract to reduce fragility between * versions. * * @since 1.6 */ public ReferenceProperty findReferenceType(AnnotatedMember member) { return null; } /** * Method called to check whether given property is marked to be "unwrapped" * when being serialized (and appropriately handled in reverse direction, * i.e. expect unwrapped representation during deserialization) * * @since 1.9 */ public Boolean shouldUnwrapProperty(AnnotatedMember member) { return null; } /** * Method called to check whether given property is marked to * be ignored; but NOT to determine if it should necessarily * be ignored, since that may depend on other factors. *

* Default implementation calls existing 'isIgnored' methods * such as {@link #isIgnorableField(AnnotatedField)} and * {@link #isIgnorableMethod(AnnotatedMethod)}. * * @since 1.9 */ public boolean hasIgnoreMarker(AnnotatedMember m) { /* For maximum backwards compatibility, we better call * existing methods. */ /* TODO: For 2.0, replace with simple 'return false;' */ if (m instanceof AnnotatedMethod) { return isIgnorableMethod((AnnotatedMethod) m); } if (m instanceof AnnotatedField) { return isIgnorableField((AnnotatedField) m); } if (m instanceof AnnotatedConstructor) { return isIgnorableConstructor((AnnotatedConstructor) m); } return false; } /** * Method called to find out whether given member expectes a value * to be injected, and if so, what is the identifier of the value * to use during injection. * Type if identifier needs to be compatible with provider of * values (of type {@link InjectableValues}); often a simple String * id is used. * * @param m Member to check * * @return Identifier of value to inject, if any; null if no injection * indicator is found */ public Object findInjectableValueId(AnnotatedMember m) { return null; } /* /********************************************************** /* General method annotations /********************************************************** */ /** * Method for checking whether there is an annotation that * indicates that given method should be ignored for all * operations (serialization, deserialization). *

* Note that this method should ONLY return true for such * explicit ignoral cases; and not if method just happens not to * be visible for annotation processor. * * @return True, if an annotation is found to indicate that the * method should be ignored; false if not. */ public abstract boolean isIgnorableMethod(AnnotatedMethod m); /** * @since 1.2 */ public abstract boolean isIgnorableConstructor(AnnotatedConstructor c); /* /********************************************************** /* General field annotations /********************************************************** */ /** * Method for checking whether there is an annotation that * indicates that given field should be ignored for all * operations (serialization, deserialization). * * @return True, if an annotation is found to indicate that the * field should be ignored; false if not. */ public abstract boolean isIgnorableField(AnnotatedField f); /* /********************************************************** /* Serialization: general annotations /********************************************************** */ /** * Method for getting a serializer definition on specified method * or field. Type of definition is either instance (of type * {@link JsonSerializer}) or Class (of type * Class); if value of different * type is returned, a runtime exception may be thrown by caller. *

* Note: this variant was briefly deprecated for 1.7; should not be */ public abstract Object findSerializer(Annotated am); /** * Method for getting a serializer definition for keys of associated Map property. * Type of definition is either instance (of type * {@link JsonSerializer}) or Class (of type * Class); if value of different * type is returned, a runtime exception may be thrown by caller. * * @since 1.8 */ public Class> findKeySerializer(Annotated am) { return null; } /** * Method for getting a serializer definition for content (values) of * associated Collection, array or Map property. * Type of definition is either instance (of type * {@link JsonSerializer}) or Class (of type * Class); if value of different * type is returned, a runtime exception may be thrown by caller. * * @since 1.8 */ public Class> findContentSerializer(Annotated am) { return null; } /** * Method for checking whether given annotated entity (class, method, * field) defines which Bean/Map properties are to be included in * serialization. * If no annotation is found, method should return given second * argument; otherwise value indicated by the annotation * * @return Enumerated value indicating which properties to include * in serialization */ public JsonSerialize.Inclusion findSerializationInclusion(Annotated a, JsonSerialize.Inclusion defValue) { return defValue; } /** * Method for accessing annotated type definition that a * method/field can have, to be used as the type for serialization * instead of the runtime type. * Type returned (if any) needs to be widening conversion (super-type). * Declared return type of the method is also considered acceptable. * * @return Class to use instead of runtime type */ public abstract Class findSerializationType(Annotated a); /** * Method for finding possible widening type definition that a property * value can have, to define less specific key type to use for serialization. * It should be only be used with {@link java.util.Map} types. * * @return Class specifying more general type to use instead of * declared type, if annotation found; null if not */ public Class findSerializationKeyType(Annotated am, JavaType baseType) { return null; } /** * Method for finding possible widening type definition that a property * value can have, to define less specific key type to use for serialization. * It should be only used with structured types (arrays, collections, maps). * * @return Class specifying more general type to use instead of * declared type, if annotation found; null if not */ public Class findSerializationContentType(Annotated am, JavaType baseType) { return null; } /** * Method for accessing declared typing mode annotated (if any). * This is used for type detection, unless more granular settings * (such as actual exact type; or serializer to use which means * no type information is needed) take precedence. * * @since 1.2 * * @return Typing mode to use, if annotation is found; null otherwise */ public abstract JsonSerialize.Typing findSerializationTyping(Annotated a); /** * Method for checking if annotated serializable property (represented by * field or getter method) has definitions for views it is to be included * in. If null is returned, no view definitions exist and property is always * included; otherwise it will only be included for views included in returned * array. View matches are checked using class inheritance rules (sub-classes * inherit inclusions of super-classes) * * @param a Annotated serializable property (field or getter method) * @return Array of views (represented by classes) that the property is included in; * if null, always included (same as returning array containing Object.class) */ public abstract Class[] findSerializationViews(Annotated a); /* /********************************************************** /* Serialization: class annotations /********************************************************** */ /** * Method for accessing defined property serialization order (which may be * partial). May return null if no ordering is defined. * * @since 1.4 */ public abstract String[] findSerializationPropertyOrder(AnnotatedClass ac); /** * Method for checking whether an annotation indicates that serialized properties * for which no explicit is defined should be alphabetically (lexicograpically) * ordered * * @since 1.4 */ public abstract Boolean findSerializationSortAlphabetically(AnnotatedClass ac); /* /********************************************************** /* Serialization: method annotations /********************************************************** */ /** * Method for checking whether given method has an annotation * that suggests property name associated with method that * may be a "getter". Should return null if no annotation * is found; otherwise a non-null String. * If non-null value is returned, it is used as the property * name, except for empty String ("") which is taken to mean * "use standard bean name detection if applicable; * method name if not". */ public abstract String findGettablePropertyName(AnnotatedMethod am); /** * Method for checking whether given method has an annotation * that suggests that the return value of annotated method * should be used as "the value" of the object instance; usually * serialized as a primitive value such as String or number. * * @return True if such annotation is found (and is not disabled); * false if no enabled annotation is found */ public abstract boolean hasAsValueAnnotation(AnnotatedMethod am); /** * Method for determining the String value to use for serializing * given enumeration entry; used when serializing enumerations * as Strings (the standard method). * * @return Serialized enum value. */ public abstract String findEnumValue(Enum value); /* /********************************************************** /* Serialization: field annotations /********************************************************** */ /** * Method for checking whether given member field represent * a serializable logical property; and if so, returns the * name of that property. * Should return null if no annotation is found (indicating it * is not a serializable field); otherwise a non-null String. * If non-null value is returned, it is used as the property * name, except for empty String ("") which is taken to mean * "use the field name as is". */ public abstract String findSerializablePropertyName(AnnotatedField af); /* /********************************************************** /* Deserialization: general annotations /********************************************************** */ /** * Method for getting a deserializer definition on specified method * or field. * Type of definition is either instance (of type * {@link JsonDeserializer}) or Class (of type * Class); if value of different * type is returned, a runtime exception may be thrown by caller. *

* Note: this variant was briefly deprecated for 1.7; but it turns out * we really should not try to push BeanProperty through at this point */ public abstract Object findDeserializer(Annotated am); /** * Method for getting a deserializer definition for keys of * associated Map property. * Type of definition is either instance (of type * {@link JsonDeserializer}) or Class (of type * Class); if value of different * type is returned, a runtime exception may be thrown by caller. * * @since 1.3 */ public abstract Class findKeyDeserializer(Annotated am); /** * Method for getting a deserializer definition for content (values) of * associated Collection, array or * Map property. * Type of definition is either instance (of type * {@link JsonDeserializer}) or Class (of type * Class); if value of different * type is returned, a runtime exception may be thrown by caller. * * @since 1.3 */ public abstract Class> findContentDeserializer(Annotated am); /** * Method for accessing annotated type definition that a * method can have, to be used as the type for serialization * instead of the runtime type. * Type must be a narrowing conversion * (i.e.subtype of declared type). * Declared return type of the method is also considered acceptable. * * @param baseType Assumed type before considering annotations * @param propName Logical property name of the property that uses * type, if known; null for types not associated with property * * @return Class to use for deserialization instead of declared type */ public abstract Class findDeserializationType(Annotated am, JavaType baseType, String propName); /** * Method for accessing additional narrowing type definition that a * method can have, to define more specific key type to use. * It should be only be used with {@link java.util.Map} types. * * @param baseKeyType Assumed key type before considering annotations * @param propName Logical property name of the property that uses * type, if known; null for types not associated with property * * @return Class specifying more specific type to use instead of * declared type, if annotation found; null if not */ public abstract Class findDeserializationKeyType(Annotated am, JavaType baseKeyType, String propName); /** * Method for accessing additional narrowing type definition that a * method can have, to define more specific content type to use; * content refers to Map values and Collection/array elements. * It should be only be used with Map, Collection and array types. * * @param baseContentType Assumed content (value) type before considering annotations * @param propName Logical property name of the property that uses * type, if known; null for types not associated with property * * @return Class specifying more specific type to use instead of * declared type, if annotation found; null if not */ public abstract Class findDeserializationContentType(Annotated am, JavaType baseContentType, String propName); /* /********************************************************** /* Deserialization: class annotations /********************************************************** */ /** * Method getting {@link ValueInstantiator} to use for given * type (class): return value can either be an instance of * instantiator, or class of instantiator to create. * * @since 1.9 */ public Object findValueInstantiator(AnnotatedClass ac) { return null; } /* /********************************************************** /* Deserialization: method annotations /********************************************************** */ /** * Method for checking whether given method has an annotation * that suggests property name associated with method that * may be a "setter". Should return null if no annotation * is found; otherwise a non-null String. * If non-null value is returned, it is used as the property * name, except for empty String ("") which is taken to mean * "use standard bean name detection if applicable; * method name if not". */ public abstract String findSettablePropertyName(AnnotatedMethod am); /** * Method for checking whether given method has an annotation * that suggests that the method is to serve as "any setter"; * method to be used for setting values of any properties for * which no dedicated setter method is found. * * @return True if such annotation is found (and is not disabled), * false otherwise */ public boolean hasAnySetterAnnotation(AnnotatedMethod am) { return false; } /** * Method for checking whether given method has an annotation * that suggests that the method is to serve as "any setter"; * method to be used for accessing set of miscellaneous "extra" * properties, often bound with matching "any setter" method. * * @return True if such annotation is found (and is not disabled), * false otherwise * * @since 1.6 */ public boolean hasAnyGetterAnnotation(AnnotatedMethod am) { return false; } /** * Method for checking whether given annotated item (method, constructor) * has an annotation * that suggests that the method is a "creator" (aka factory) * method to be used for construct new instances of deserialized * values. * * @return True if such annotation is found (and is not disabled), * false otherwise */ public boolean hasCreatorAnnotation(Annotated a) { return false; } /* /********************************************************** /* Deserialization: field annotations /********************************************************** */ /** * Method for checking whether given member field represent * a deserializable logical property; and if so, returns the * name of that property. * Should return null if no annotation is found (indicating it * is not a deserializable field); otherwise a non-null String. * If non-null value is returned, it is used as the property * name, except for empty String ("") which is taken to mean * "use the field name as is". */ public abstract String findDeserializablePropertyName(AnnotatedField af); /* /********************************************************** /* Deserialization: parameter annotations (for /* creator method parameters) /********************************************************** */ /** * Method for checking whether given set of annotations indicates * property name for associated parameter. * No actual parameter object can be passed since JDK offers no * representation; just annotations. */ public abstract String findPropertyNameForParam(AnnotatedParameter param); /* /********************************************************** /* Helper classes /********************************************************** */ /** * Helper class that allows using 2 introspectors such that one * introspector acts as the primary one to use; and second one * as a fallback used if the primary does not provide conclusive * or useful result for a method. *

* An obvious consequence of priority is that it is easy to construct * longer chains of introspectors by linking multiple pairs. * Currently most likely combination is that of using the default * Jackson provider, along with JAXB annotation introspector (available * since version 1.1). */ public static class Pair extends AnnotationIntrospector { protected final AnnotationIntrospector _primary, _secondary; public Pair(AnnotationIntrospector p, AnnotationIntrospector s) { _primary = p; _secondary = s; } /** * Helper method for constructing a Pair from two given introspectors (if * neither is null); or returning non-null introspector if one is null * (and return just null if both are null) * * @since 1.7 */ public static AnnotationIntrospector create(AnnotationIntrospector primary, AnnotationIntrospector secondary) { if (primary == null) { return secondary; } if (secondary == null) { return primary; } return new Pair(primary, secondary); } @Override public Collection allIntrospectors() { return allIntrospectors(new ArrayList()); } @Override public Collection allIntrospectors(Collection result) { _primary.allIntrospectors(result); _secondary.allIntrospectors(result); return result; } // // // Generic annotation properties, lookup @Override public boolean isHandled(Annotation ann) { return _primary.isHandled(ann) || _secondary.isHandled(ann); } /* /****************************************************** /* General class annotations /****************************************************** */ @Override public Boolean findCachability(AnnotatedClass ac) { Boolean result = _primary.findCachability(ac); if (result == null) { result = _secondary.findCachability(ac); } return result; } @Override public String findRootName(AnnotatedClass ac) { String name1 = _primary.findRootName(ac); if (name1 == null) { return _secondary.findRootName(ac); } else if (name1.length() > 0) { return name1; } // name1 is empty; how about secondary? String name2 = _secondary.findRootName(ac); return (name2 == null) ? name1 : name2; } @Override public String[] findPropertiesToIgnore(AnnotatedClass ac) { String[] result = _primary.findPropertiesToIgnore(ac); if (result == null) { result = _secondary.findPropertiesToIgnore(ac); } return result; } @Override public Boolean findIgnoreUnknownProperties(AnnotatedClass ac) { Boolean result = _primary.findIgnoreUnknownProperties(ac); if (result == null) { result = _secondary.findIgnoreUnknownProperties(ac); } return result; } @Override public Boolean isIgnorableType(AnnotatedClass ac) { Boolean result = _primary.isIgnorableType(ac); if (result == null) { result = _secondary.isIgnorableType(ac); } return result; } @Override public Object findFilterId(AnnotatedClass ac) { Object id = _primary.findFilterId(ac); if (id == null) { id = _secondary.findFilterId(ac); } return id; } /* /****************************************************** /* Property auto-detection /****************************************************** */ @Override public VisibilityChecker findAutoDetectVisibility(AnnotatedClass ac, VisibilityChecker checker) { /* Note: to have proper priorities, we must actually call delegatees * in reverse order: */ checker = _secondary.findAutoDetectVisibility(ac, checker); return _primary.findAutoDetectVisibility(ac, checker); } /* /****************************************************** /* Type handling /****************************************************** */ @Override public TypeResolverBuilder findTypeResolver(MapperConfig config, AnnotatedClass ac, JavaType baseType) { TypeResolverBuilder b = _primary.findTypeResolver(config, ac, baseType); if (b == null) { b = _secondary.findTypeResolver(config, ac, baseType); } return b; } @Override public TypeResolverBuilder findPropertyTypeResolver(MapperConfig config, AnnotatedMember am, JavaType baseType) { TypeResolverBuilder b = _primary.findPropertyTypeResolver(config, am, baseType); if (b == null) { b = _secondary.findPropertyTypeResolver(config, am, baseType); } return b; } @Override public TypeResolverBuilder findPropertyContentTypeResolver(MapperConfig config, AnnotatedMember am, JavaType baseType) { TypeResolverBuilder b = _primary.findPropertyContentTypeResolver(config, am, baseType); if (b == null) { b = _secondary.findPropertyContentTypeResolver(config, am, baseType); } return b; } @Override public List findSubtypes(Annotated a) { List types1 = _primary.findSubtypes(a); List types2 = _secondary.findSubtypes(a); if (types1 == null || types1.isEmpty()) return types2; if (types2 == null || types2.isEmpty()) return types1; ArrayList result = new ArrayList(types1.size() + types2.size()); result.addAll(types1); result.addAll(types2); return result; } @Override public String findTypeName(AnnotatedClass ac) { String name = _primary.findTypeName(ac); if (name == null || name.length() == 0) { name = _secondary.findTypeName(ac); } return name; } // // // General member (field, method/constructor) annotations @Override public ReferenceProperty findReferenceType(AnnotatedMember member) { ReferenceProperty ref = _primary.findReferenceType(member); if (ref == null) { ref = _secondary.findReferenceType(member); } return ref; } @Override public Boolean shouldUnwrapProperty(AnnotatedMember member) { Boolean value = _primary.shouldUnwrapProperty(member); if (value == null) { value = _secondary.shouldUnwrapProperty(member); } return value; } @Override public Object findInjectableValueId(AnnotatedMember m) { Object value = _primary.findInjectableValueId(m); if (value == null) { value = _secondary.findInjectableValueId(m); } return value; } @Override public boolean hasIgnoreMarker(AnnotatedMember m) { return _primary.hasIgnoreMarker(m) || _secondary.hasIgnoreMarker(m); } // // // General method annotations @Override public boolean isIgnorableMethod(AnnotatedMethod m) { return _primary.isIgnorableMethod(m) || _secondary.isIgnorableMethod(m); } @Override public boolean isIgnorableConstructor(AnnotatedConstructor c) { return _primary.isIgnorableConstructor(c) || _secondary.isIgnorableConstructor(c); } // // // General field annotations @Override public boolean isIgnorableField(AnnotatedField f) { return _primary.isIgnorableField(f) || _secondary.isIgnorableField(f); } // // // Serialization: general annotations @Override public Object findSerializer(Annotated am) { Object result = _primary.findSerializer(am); if (result == null) { result = _secondary.findSerializer(am); } return result; } @Override public Class> findKeySerializer(Annotated a) { Class> result = _primary.findKeySerializer(a); if (result == null || result == JsonSerializer.None.class) { result = _secondary.findKeySerializer(a); } return result; } @Override public Class> findContentSerializer(Annotated a) { Class> result = _primary.findContentSerializer(a); if (result == null || result == JsonSerializer.None.class) { result = _secondary.findContentSerializer(a); } return result; } @Override public JsonSerialize.Inclusion findSerializationInclusion(Annotated a, JsonSerialize.Inclusion defValue) { /* This is bit trickier: need to combine results in a meaningful * way. Seems like it should be a disjoint; that is, most * restrictive value should be returned. * For enumerations, comparison is done by indexes, which * works: largest value is the last one, which is the most * restrictive value as well. */ /* 09-Mar-2010, tatu: Actually, as per [JACKSON-256], it is probably better to just * use strict overriding. Simpler, easier to understand. */ // note: call secondary first, to give lower priority defValue = _secondary.findSerializationInclusion(a, defValue); defValue = _primary.findSerializationInclusion(a, defValue); return defValue; } @Override public Class findSerializationType(Annotated a) { Class result = _primary.findSerializationType(a); if (result == null) { result = _secondary.findSerializationType(a); } return result; } @Override public Class findSerializationKeyType(Annotated am, JavaType baseType) { Class result = _primary.findSerializationKeyType(am, baseType); if (result == null) { result = _secondary.findSerializationKeyType(am, baseType); } return result; } @Override public Class findSerializationContentType(Annotated am, JavaType baseType) { Class result = _primary.findSerializationContentType(am, baseType); if (result == null) { result = _secondary.findSerializationContentType(am, baseType); } return result; } @Override public JsonSerialize.Typing findSerializationTyping(Annotated a) { JsonSerialize.Typing result = _primary.findSerializationTyping(a); if (result == null) { result = _secondary.findSerializationTyping(a); } return result; } @Override public Class[] findSerializationViews(Annotated a) { /* Theoretically this could be trickier, if multiple introspectors * return non-null entries. For now, though, we'll just consider * first one to return non-null to win. */ Class[] result = _primary.findSerializationViews(a); if (result == null) { result = _secondary.findSerializationViews(a); } return result; } // // // Serialization: class annotations @Override public String[] findSerializationPropertyOrder(AnnotatedClass ac) { String[] result = _primary.findSerializationPropertyOrder(ac); if (result == null) { result = _secondary.findSerializationPropertyOrder(ac); } return result; } /** * Method for checking whether an annotation indicates that serialized properties * for which no explicit is defined should be alphabetically (lexicograpically) * ordered */ @Override public Boolean findSerializationSortAlphabetically(AnnotatedClass ac) { Boolean result = _primary.findSerializationSortAlphabetically(ac); if (result == null) { result = _secondary.findSerializationSortAlphabetically(ac); } return result; } // // // Serialization: method annotations @Override public String findGettablePropertyName(AnnotatedMethod am) { String result = _primary.findGettablePropertyName(am); if (result == null) { result = _secondary.findGettablePropertyName(am); } else if (result.length() == 0) { /* Empty String is a default; can be overridden by * more explicit answer from secondary entry */ String str2 = _secondary.findGettablePropertyName(am); if (str2 != null) { result = str2; } } return result; } @Override public boolean hasAsValueAnnotation(AnnotatedMethod am) { return _primary.hasAsValueAnnotation(am) || _secondary.hasAsValueAnnotation(am); } @Override public String findEnumValue(Enum value) { String result = _primary.findEnumValue(value); if (result == null) { result = _secondary.findEnumValue(value); } return result; } // // // Serialization: field annotations @Override public String findSerializablePropertyName(AnnotatedField af) { String result = _primary.findSerializablePropertyName(af); if (result == null) { result = _secondary.findSerializablePropertyName(af); } else if (result.length() == 0) { /* Empty String is a default; can be overridden by * more explicit answer from secondary entry */ String str2 = _secondary.findSerializablePropertyName(af); if (str2 != null) { result = str2; } } return result; } // // // Deserialization: general annotations @Override public Object findDeserializer(Annotated am) { Object result = _primary.findDeserializer(am); if (result == null) { result = _secondary.findDeserializer(am); } return result; } @Override public Class findKeyDeserializer(Annotated am) { Class result = _primary.findKeyDeserializer(am); if (result == null || result == KeyDeserializer.None.class) { result = _secondary.findKeyDeserializer(am); } return result; } @Override public Class> findContentDeserializer(Annotated am) { Class> result = _primary.findContentDeserializer(am); if (result == null || result == JsonDeserializer.None.class) { result = _secondary.findContentDeserializer(am); } return result; } @Override public Class findDeserializationType(Annotated am, JavaType baseType, String propName) { Class result = _primary.findDeserializationType(am, baseType, propName); if (result == null) { result = _secondary.findDeserializationType(am, baseType, propName); } return result; } @Override public Class findDeserializationKeyType(Annotated am, JavaType baseKeyType, String propName) { Class result = _primary.findDeserializationKeyType(am, baseKeyType, propName); if (result == null) { result = _secondary.findDeserializationKeyType(am, baseKeyType, propName); } return result; } @Override public Class findDeserializationContentType(Annotated am, JavaType baseContentType, String propName) { Class result = _primary.findDeserializationContentType(am, baseContentType, propName); if (result == null) { result = _secondary.findDeserializationContentType(am, baseContentType, propName); } return result; } // // // Deserialization: class annotations @Override public Object findValueInstantiator(AnnotatedClass ac) { Object result = _primary.findValueInstantiator(ac); if (result == null) { result = _secondary.findValueInstantiator(ac); } return result; } // // // Deserialization: method annotations @Override public String findSettablePropertyName(AnnotatedMethod am) { String result = _primary.findSettablePropertyName(am); if (result == null) { result = _secondary.findSettablePropertyName(am); } else if (result.length() == 0) { /* Empty String is a default; can be overridden by * more explicit answer from secondary entry */ String str2 = _secondary.findSettablePropertyName(am); if (str2 != null) { result = str2; } } return result; } @Override public boolean hasAnySetterAnnotation(AnnotatedMethod am) { return _primary.hasAnySetterAnnotation(am) || _secondary.hasAnySetterAnnotation(am); } @Override public boolean hasAnyGetterAnnotation(AnnotatedMethod am) { return _primary.hasAnyGetterAnnotation(am) || _secondary.hasAnyGetterAnnotation(am); } @Override public boolean hasCreatorAnnotation(Annotated a) { return _primary.hasCreatorAnnotation(a) || _secondary.hasCreatorAnnotation(a); } // // // Deserialization: field annotations @Override public String findDeserializablePropertyName(AnnotatedField af) { String result = _primary.findDeserializablePropertyName(af); if (result == null) { result = _secondary.findDeserializablePropertyName(af); } else if (result.length() == 0) { /* Empty String is a default; can be overridden by * more explicit answer from secondary entry */ String str2 = _secondary.findDeserializablePropertyName(af); if (str2 != null) { result = str2; } } return result; } // // // Deserialization: parameter annotations (for creators) @Override public String findPropertyNameForParam(AnnotatedParameter param) { String result = _primary.findPropertyNameForParam(param); if (result == null) { result = _secondary.findPropertyNameForParam(param); } return result; } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/SerializationConfig.java0000644000175000017500000011413111655120726031011 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.text.DateFormat; import java.util.*; import org.codehaus.jackson.annotate.*; import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion; // for javadocs import org.codehaus.jackson.map.introspect.Annotated; import org.codehaus.jackson.map.introspect.AnnotatedClass; import org.codehaus.jackson.map.introspect.VisibilityChecker; import org.codehaus.jackson.map.jsontype.SubtypeResolver; import org.codehaus.jackson.map.jsontype.TypeResolverBuilder; import org.codehaus.jackson.map.ser.FilterProvider; import org.codehaus.jackson.map.type.ClassKey; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.map.util.ClassUtil; import org.codehaus.jackson.type.JavaType; /** * Object that contains baseline configuration for serialization * process. An instance is owned by {@link ObjectMapper}, which makes * a copy that is passed during serialization process to * {@link SerializerProvider} and {@link SerializerFactory}. *

* Note: although configuration settings can be changed at any time * (for factories and instances), they are not guaranteed to have * effect if called after constructing relevant mapper or serializer * instance. This because some objects may be configured, constructed and * cached first time they are needed. *

* As of version 1.9, the goal is to make this class eventually immutable. * Because of this, existing methods that allow changing state of this * instance are deprecated in favor of methods that create new instances * with different configuration ("fluent factories") */ public class SerializationConfig extends MapperConfig.Impl { /** * Enumeration that defines togglable features that guide * the serialization feature. */ public enum Feature implements MapperConfig.ConfigFeature { /* /****************************************************** /* Introspection features /****************************************************** */ /** * Feature that determines whether annotation introspection * is used for configuration; if enabled, configured * {@link AnnotationIntrospector} will be used: if disabled, * no annotations are considered. *

* Feature is enabled by default. * * @since 1.2 */ USE_ANNOTATIONS(true), /** * Feature that determines whether regualr "getter" methods are * automatically detected based on standard Bean naming convention * or not. If yes, then all public zero-argument methods that * start with prefix "get" * are considered as getters. * If disabled, only methods explicitly annotated are considered getters. *

* Note that since version 1.3, this does NOT include * "is getters" (see {@link #AUTO_DETECT_IS_GETTERS} for details) *

* Note that this feature has lower precedence than per-class * annotations, and is only used if there isn't more granular * configuration available. *

* Feature is enabled by default. */ AUTO_DETECT_GETTERS(true), /** * Feature that determines whether "is getter" methods are * automatically detected based on standard Bean naming convention * or not. If yes, then all public zero-argument methods that * start with prefix "is", and whose return type is boolean * are considered as "is getters". * If disabled, only methods explicitly annotated are considered getters. *

* Note that this feature has lower precedence than per-class * annotations, and is only used if there isn't more granular * configuration available. *

* Feature is enabled by default. */ AUTO_DETECT_IS_GETTERS(true), /** * Feature that determines whether non-static fields are recognized as * properties. * If yes, then all public member fields * are considered as properties. If disabled, only fields explicitly * annotated are considered property fields. *

* Note that this feature has lower precedence than per-class * annotations, and is only used if there isn't more granular * configuration available. *

* Feature is enabled by default. * * @since 1.1 */ AUTO_DETECT_FIELDS(true), /** * Feature that determines whether method and field access * modifier settings can be overridden when accessing * properties. If enabled, method * {@link java.lang.reflect.AccessibleObject#setAccessible} * may be called to enable access to otherwise unaccessible * objects. *

* Feature is enabled by default. */ CAN_OVERRIDE_ACCESS_MODIFIERS(true), /** * Feature that determines whether getters (getter methods) * can be auto-detected if there is no matching mutator (setter, * constructor parameter or field) or not: if set to true, * only getters that match a mutator are auto-discovered; if * false, all auto-detectable getters can be discovered. *

* Feature is disabled by default for backwards compatibility * reasons. * * @since 1.9 */ REQUIRE_SETTERS_FOR_GETTERS(false), /* /****************************************************** /* Generic output features /****************************************************** */ /** * Feature that determines the default settings of whether Bean * properties with null values are to be written out. *

* Feature is enabled by default (null properties written). *

* Note too that there is annotation * {@link org.codehaus.jackson.annotate.JsonWriteNullProperties} * that can be used for more granular control (annotates bean * classes or individual property access methods). * * @deprecated As of 1.1, use {@link SerializationConfig#setSerializationInclusion} * instead */ @Deprecated WRITE_NULL_PROPERTIES(true), /** * Feature that determines whether the type detection for * serialization should be using actual dynamic runtime type, * or declared static type. * Default value is false, to use dynamic runtime type. *

* This global default value can be overridden at class, method * or field level by using {@link JsonSerialize#typing} annotation * property */ USE_STATIC_TYPING(false), /** * Feature that determines whether properties that have no view * annotations are included in JSON serialization views (see * {@link org.codehaus.jackson.map.annotate.JsonView} for more * details on JSON Views). * If enabled, non-annotated properties will be included; * when disabled, they will be excluded. So this feature * changes between "opt-in" (feature disabled) and * "opt-out" (feature enabled) modes. *

* Default value is enabled, meaning that non-annotated * properties are included in all views if there is no * {@link org.codehaus.jackson.map.annotate.JsonView} annotation. * * @since 1.5 */ DEFAULT_VIEW_INCLUSION(true), /** * Feature that can be enabled to make root value (usually JSON * Object but can be any type) wrapped within a single property * JSON object, where key as the "root name", as determined by * annotation introspector (esp. for JAXB that uses * @XmlRootElement.name) or fallback (non-qualified * class name). * Feature is mostly intended for JAXB compatibility. *

* Default setting is false, meaning root value is not wrapped. * * @since 1.7 */ WRAP_ROOT_VALUE(false), /** * Feature that allows enabling (or disabling) indentation * for the underlying generator, using the default pretty * printer (see * {@link org.codehaus.jackson.JsonGenerator#useDefaultPrettyPrinter} * for details). *

* Note that this only affects cases where * {@link org.codehaus.jackson.JsonGenerator} * is constructed implicitly by ObjectMapper: if explicit * generator is passed, its configuration is not changed. *

* Also note that if you want to configure details of indentation, * you need to directly configure the generator: there is a * method to use any PrettyPrinter instance. * This feature will only allow using the default implementation. */ INDENT_OUTPUT(false), /** * Feature that defines default property serialization order used * for POJO fields (note: does not apply to {@link java.util.Map} * serialization!): * if enabled, default ordering is alphabetic (similar to * how {@link org.codehaus.jackson.annotate.JsonPropertyOrder#alphabetic()} * works); if disabled, order is unspecified (based on what JDK gives * us, which may be declaration order, but not guaranteed). *

* Note that this is just the default behavior, and can be overridden by * explicit overrides in classes. * * @since 1.8 */ SORT_PROPERTIES_ALPHABETICALLY(false), /* /****************************************************** /* Error handling features /****************************************************** */ /** * Feature that determines what happens when no accessors are * found for a type (and there are no annotations to indicate * it is meant to be serialized). If enabled (default), an * exception is thrown to indicate these as non-serializable * types; if disabled, they are serialized as empty Objects, * i.e. without any properties. *

* Note that empty types that this feature has only effect on * those "empty" beans that do not have any recognized annotations * (like @JsonSerialize): ones that do have annotations * do not result in an exception being thrown. * * @since 1.4 */ FAIL_ON_EMPTY_BEANS(true), /** * Feature that determines whether Jackson code should catch * and wrap {@link Exception}s (but never {@link Error}s!) * to add additional information about * location (within input) of problem or not. If enabled, * most exceptions will be caught and re-thrown (exception * specifically being that {@link java.io.IOException}s may be passed * as is, since they are declared as throwable); this can be * convenient both in that all exceptions will be checked and * declared, and so there is more contextual information. * However, sometimes calling application may just want "raw" * unchecked exceptions passed as is. *

* Feature is enabled by default, and is similar in behavior * to default prior to 1.7. * * @since 1.7 */ WRAP_EXCEPTIONS(true), /* /****************************************************** /* Output life cycle features /****************************************************** */ /** * Feature that determines whether close method of * serialized root level objects (ones for which ObjectMapper's * writeValue() (or equivalent) method is called) * that implement {@link java.io.Closeable} * is called after serialization or not. If enabled, close() will * be called after serialization completes (whether succesfully, or * due to an error manifested by an exception being thrown). You can * think of this as sort of "finally" processing. *

* NOTE: only affects behavior with root objects, and not other * objects reachable from the root object. Put another way, only one * call will be made for each 'writeValue' call. * * @since 1.6 (see [JACKSON-282 for details]) */ CLOSE_CLOSEABLE(false), /** * Feature that determines whether JsonGenerator.flush() is * called after writeValue() method that takes JsonGenerator * as an argument completes (i.e. does NOT affect methods * that use other destinations); same for methods in {@link ObjectWriter}. * This usually makes sense; but there are cases where flushing * should not be forced: for example when underlying stream is * compressing and flush() causes compression state to be flushed * (which occurs with some compression codecs). * * @since 1.6 (see [JACKSON-401 for details]) */ FLUSH_AFTER_WRITE_VALUE(true), /* /****************************************************** /* Data type - specific serialization configuration /****************************************************** */ /** * Feature that determines whether {@link java.util.Date} values * (and Date-based things like {@link java.util.Calendar}s) are to be * serialized as numeric timestamps (true; the default), * or as something else (usually textual representation). * If textual representation is used, the actual format is * one returned by a call to {@link #getDateFormat}. *

* Note: whether this feature affects handling of other date-related * types depend on handlers of those types, although ideally they * should use this feature *

* Note: whether {@link java.util.Map} keys are serialized as Strings * or not is controlled using {@link #WRITE_DATE_KEYS_AS_TIMESTAMPS}. */ WRITE_DATES_AS_TIMESTAMPS(true), /** * Feature that determines whether {@link java.util.Date}s * (and sub-types) used as {@link java.util.Map} keys are serialized * as timestamps or not (if not, will be serialized as textual * values). *

* Default value is 'false', meaning that Date-valued Map keys are serialized * as textual (ISO-8601) values. * * @since 1.9 */ WRITE_DATE_KEYS_AS_TIMESTAMPS(false), /** * Feature that determines how type char[] is serialized: * when enabled, will be serialized as an explict JSON array (with * single-character Strings as values); when disabled, defaults to * serializing them as Strings (which is more compact). * * @since 1.6 (see [JACKSON-289 for details]) */ WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS(false), /** * Feature that determines standard serialization mechanism used for * Enum values: if enabled, return value of Enum.toString() * is used; if disabled, return value of Enum.name() is used. * Since pre-1.6 method was to use Enum name, this is the default. *

* Note: this feature should usually have same value * as {@link DeserializationConfig.Feature#READ_ENUMS_USING_TO_STRING}. *

* For further details, check out [JACKSON-212] * * @since 1.6 */ WRITE_ENUMS_USING_TO_STRING(false), /** * Feature that determines whethere Java Enum values are serialized * as numbers (true), or textual values (false). If textual values are * used, other settings are also considered. * If this feature is enabled, * return value of Enum.ordinal() * (an integer) will be used as the serialization. *

* Note that this feature has precedence over {@link #WRITE_ENUMS_USING_TO_STRING}, * which is only considered if this feature is set to false. * * @since 1.9 */ WRITE_ENUMS_USING_INDEX(false), /** * Feature that determines whether Map entries with null values are * to be serialized (true) or not (false). *

* For further details, check out [JACKSON-314] * * @since 1.6 */ WRITE_NULL_MAP_VALUES(true), /** * Feature that determines whether Container properties (POJO properties * with declared value of Collection or array; i.e. things that produce JSON * arrays) that are empty (have no elements) * will be serialized as empty JSON arrays (true), or suppressed from output (false). *

* Note that this does not change behavior of {@link java.util.Map}s, or * "Collection-like" types. * * @since 1.9 */ WRITE_EMPTY_JSON_ARRAYS(true) ; final boolean _defaultState; private Feature(boolean defaultState) { _defaultState = defaultState; } @Override public boolean enabledByDefault() { return _defaultState; } @Override public int getMask() { return (1 << ordinal()); } } /* /********************************************************** /* Configuration settings /********************************************************** */ /** * Which Bean/Map properties are to be included in serialization? * Default settings is to include all regardless of value; can be * changed to only include non-null properties, or properties * with non-default values. *

* Defaults to null for backwards compatibility; if left as null, * will check * deprecated {@link Feature#WRITE_NULL_PROPERTIES} * to choose between {@link Inclusion#ALWAYS} * and {@link Inclusion#NON_NULL}. */ protected JsonSerialize.Inclusion _serializationInclusion = null; /** * View to use for filtering out properties to serialize. * Null if none (will also be assigned null if Object.class * is defined), meaning that all properties are to be included. */ protected Class _serializationView; /** * Object used for resolving filter ids to filter instances. * Non-null if explicitly defined; null by default. * * @since 1.7 */ protected FilterProvider _filterProvider; /* /********************************************************** /* Life-cycle, constructors /********************************************************** */ /** * Constructor used by ObjectMapper to create default configuration object instance. */ public SerializationConfig(ClassIntrospector intr, AnnotationIntrospector annIntr, VisibilityChecker vc, SubtypeResolver subtypeResolver, PropertyNamingStrategy propertyNamingStrategy, TypeFactory typeFactory, HandlerInstantiator handlerInstantiator) { super(intr, annIntr, vc, subtypeResolver, propertyNamingStrategy, typeFactory, handlerInstantiator, collectFeatureDefaults(SerializationConfig.Feature.class)); _filterProvider = null; } /** * @since 1.8 */ protected SerializationConfig(SerializationConfig src) { this(src, src._base); } /** * Constructor used to make a private copy of specific mix-in definitions. * * @since 1.8 */ protected SerializationConfig(SerializationConfig src, HashMap> mixins, SubtypeResolver str) { this(src, src._base); _mixInAnnotations = mixins; _subtypeResolver = str; } /** * @since 1.8 */ protected SerializationConfig(SerializationConfig src, MapperConfig.Base base) { super(src, base, src._subtypeResolver); _serializationInclusion = src._serializationInclusion; _serializationView = src._serializationView; _filterProvider = src._filterProvider; } /** * @since 1.8 */ protected SerializationConfig(SerializationConfig src, FilterProvider filters) { super(src); _serializationInclusion = src._serializationInclusion; _serializationView = src._serializationView; _filterProvider = filters; } /** * @since 1.8 */ protected SerializationConfig(SerializationConfig src, Class view) { super(src); _serializationInclusion = src._serializationInclusion; _serializationView = view; _filterProvider = src._filterProvider; } /** * @since 1.9 */ protected SerializationConfig(SerializationConfig src, JsonSerialize.Inclusion incl) { super(src); _serializationInclusion = incl; // And for some level of backwards compatibility, also... if (incl == JsonSerialize.Inclusion.NON_NULL) { _featureFlags &= ~Feature.WRITE_NULL_PROPERTIES.getMask(); } else { _featureFlags |= Feature.WRITE_NULL_PROPERTIES.getMask(); } _serializationView = src._serializationView; _filterProvider = src._filterProvider; } /** * @since 1.9 */ protected SerializationConfig(SerializationConfig src, int features) { super(src, features); _serializationInclusion = src._serializationInclusion; _serializationView = src._serializationView; _filterProvider = src._filterProvider; } /* /********************************************************** /* Life-cycle, factory methods from MapperConfig /********************************************************** */ @Override public SerializationConfig withClassIntrospector(ClassIntrospector ci) { return new SerializationConfig(this, _base.withClassIntrospector(ci)); } @Override public SerializationConfig withAnnotationIntrospector(AnnotationIntrospector ai) { return new SerializationConfig(this, _base.withAnnotationIntrospector(ai)); } @Override public SerializationConfig withInsertedAnnotationIntrospector(AnnotationIntrospector ai) { return new SerializationConfig(this, _base.withInsertedAnnotationIntrospector(ai)); } @Override public SerializationConfig withAppendedAnnotationIntrospector(AnnotationIntrospector ai) { return new SerializationConfig(this, _base.withAppendedAnnotationIntrospector(ai)); } @Override public SerializationConfig withVisibilityChecker(VisibilityChecker vc) { return new SerializationConfig(this, _base.withVisibilityChecker(vc)); } @Override public SerializationConfig withVisibility(JsonMethod forMethod, JsonAutoDetect.Visibility visibility) { return new SerializationConfig(this, _base.withVisibility(forMethod, visibility)); } @Override public SerializationConfig withTypeResolverBuilder(TypeResolverBuilder trb) { return new SerializationConfig(this, _base.withTypeResolverBuilder(trb)); } @Override public SerializationConfig withSubtypeResolver(SubtypeResolver str) { SerializationConfig cfg = new SerializationConfig(this); cfg._subtypeResolver = str; return cfg; } @Override public SerializationConfig withPropertyNamingStrategy(PropertyNamingStrategy pns) { return new SerializationConfig(this, _base.withPropertyNamingStrategy(pns)); } @Override public SerializationConfig withTypeFactory(TypeFactory tf) { return new SerializationConfig(this, _base.withTypeFactory(tf)); } /** * In addition to constructing instance with specified date format, * will enable or disable Feature.WRITE_DATES_AS_TIMESTAMPS * (enable if format set as null; disable if non-null) */ @Override public SerializationConfig withDateFormat(DateFormat df) { SerializationConfig cfg = new SerializationConfig(this, _base.withDateFormat(df)); // Also need to toggle this feature based on existence of date format: if (df == null) { cfg = cfg.with(Feature.WRITE_DATES_AS_TIMESTAMPS); } else { cfg = cfg.without(Feature.WRITE_DATES_AS_TIMESTAMPS); } return cfg; } @Override public SerializationConfig withHandlerInstantiator(HandlerInstantiator hi) { return new SerializationConfig(this, _base.withHandlerInstantiator(hi)); } /* /********************************************************** /* Life-cycle, SerializationConfig specific factory methods /********************************************************** */ /** * @since 1.7 */ public SerializationConfig withFilters(FilterProvider filterProvider) { return new SerializationConfig(this, filterProvider); } /** * @since 1.8 */ public SerializationConfig withView(Class view) { return new SerializationConfig(this, view); } /** * @since 1.9 */ public SerializationConfig withSerializationInclusion(JsonSerialize.Inclusion incl) { return new SerializationConfig(this, incl); } /** * Fluent factory method that will construct and return a new configuration * object instance with specified features enabled. * * @since 1.9 */ @Override public SerializationConfig with(Feature... features) { int flags = _featureFlags; for (Feature f : features) { flags |= f.getMask(); } return new SerializationConfig(this, flags); } /** * Fluent factory method that will construct and return a new configuration * object instance with specified features disabled. * * @since 1.9 */ @Override public SerializationConfig without(Feature... features) { int flags = _featureFlags; for (Feature f : features) { flags &= ~f.getMask(); } return new SerializationConfig(this, flags); } /* /********************************************************** /* MapperConfig implementation/overrides /********************************************************** */ /** * Method that checks class annotations that the argument Object has, * and modifies settings of this configuration object accordingly, * similar to how those annotations would affect actual value classes * annotated with them, but with global scope. Note that not all * annotations have global significance, and thus only subset of * Jackson annotations will have any effect. *

* Serialization annotations that are known to have effect are: *

    *
  • {@link JsonWriteNullProperties}
  • *
  • {@link JsonAutoDetect}
  • *
  • {@link JsonSerialize#typing}
  • *
* * @param cls Class of which class annotations to use * for changing configuration settings * * @deprecated Since 1.9, it is preferably to explicitly configure * instances; this method also modifies existing instance which is * against immutable design goals of this class. */ @SuppressWarnings("deprecation") @Deprecated @Override public void fromAnnotations(Class cls) { /* 10-Jul-2009, tatu: Should be able to just pass null as * 'MixInResolver'; no mix-ins set at this point * 29-Jul-2009, tatu: Also, we do NOT ignore annotations here, even * if Feature.USE_ANNOTATIONS was disabled, since caller * specifically requested annotations to be added with this call */ AnnotationIntrospector ai = getAnnotationIntrospector(); AnnotatedClass ac = AnnotatedClass.construct(cls, ai, null); _base = _base.withVisibilityChecker(ai.findAutoDetectVisibility(ac, getDefaultVisibilityChecker())); // How about writing null property values? JsonSerialize.Inclusion incl = ai.findSerializationInclusion(ac, null); if (incl != _serializationInclusion) { setSerializationInclusion(incl); } JsonSerialize.Typing typing = ai.findSerializationTyping(ac); if (typing != null) { set(Feature.USE_STATIC_TYPING, (typing == JsonSerialize.Typing.STATIC)); } } @Override public SerializationConfig createUnshared(SubtypeResolver subtypeResolver) { HashMap> mixins = _mixInAnnotations; _mixInAnnotationsShared = true; return new SerializationConfig(this, mixins, subtypeResolver); } @Override public AnnotationIntrospector getAnnotationIntrospector() { /* 29-Jul-2009, tatu: it's now possible to disable use of * annotations; can be done using "no-op" introspector */ if (isEnabled(Feature.USE_ANNOTATIONS)) { return super.getAnnotationIntrospector(); } return AnnotationIntrospector.nopInstance(); } /** * Accessor for getting bean description that only contains class * annotations: useful if no getter/setter/creator information is needed. *

* Note: part of {@link MapperConfig} since 1.7 */ @SuppressWarnings("unchecked") @Override public T introspectClassAnnotations(JavaType type) { return (T) getClassIntrospector().forClassAnnotations(this, type, this); } /** * Accessor for getting bean description that only contains immediate class * annotations: ones from the class, and its direct mix-in, if any, but * not from super types. *

* Note: part of {@link MapperConfig} since 1.7 */ @SuppressWarnings("unchecked") @Override public T introspectDirectClassAnnotations(JavaType type) { return (T) getClassIntrospector().forDirectClassAnnotations(this, type, this); } @Override public boolean isAnnotationProcessingEnabled() { return isEnabled(SerializationConfig.Feature.USE_ANNOTATIONS); } @Override public boolean canOverrideAccessModifiers() { return isEnabled(Feature.CAN_OVERRIDE_ACCESS_MODIFIERS); } @Override public boolean shouldSortPropertiesAlphabetically() { return isEnabled(Feature.SORT_PROPERTIES_ALPHABETICALLY); } @Override public VisibilityChecker getDefaultVisibilityChecker() { VisibilityChecker vchecker = super.getDefaultVisibilityChecker(); if (!isEnabled(SerializationConfig.Feature.AUTO_DETECT_GETTERS)) { vchecker = vchecker.withGetterVisibility(Visibility.NONE); } // then global overrides (disabling) if (!isEnabled(SerializationConfig.Feature.AUTO_DETECT_IS_GETTERS)) { vchecker = vchecker.withIsGetterVisibility(Visibility.NONE); } if (!isEnabled(SerializationConfig.Feature.AUTO_DETECT_FIELDS)) { vchecker = vchecker.withFieldVisibility(Visibility.NONE); } return vchecker; } /* /********************************************************** /* MapperConfig overrides for 1.8 backwards compatibility /********************************************************** */ /* NOTE: these are overloads we MUST have, but that were missing * from 1.9.0 and 1.9.1. Type erasure can bite in the ass... *

* NOTE: will remove either these variants, or base class one, in 2.0. */ /** * Alias for {@link MapperConfig#isEnabled(org.codehaus.jackson.map.MapperConfig.ConfigFeature)}. * * @since 1.0 However, note that version 1.9.0 and 1.9.1 accidentally missed * this overloaded variant */ public boolean isEnabled(SerializationConfig.Feature f) { return (_featureFlags & f.getMask()) != 0; } /** * @deprecated Since 1.9, it is preferable to use {@link #with} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated @Override public void enable(SerializationConfig.Feature f) { super.enable(f); } /** * @deprecated Since 1.9, it is preferable to use {@link #without} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated @Override public void disable(SerializationConfig.Feature f) { super.disable(f); } /** * @deprecated Since 1.9, it is preferable to use {@link #without} and {@link #with} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated @Override public void set(SerializationConfig.Feature f, boolean state) { super.set(f, state); } /* /********************************************************** /* Configuration: other /********************************************************** */ /** * Method for checking which serialization view is being used, * if any; null if none. * * @since 1.4 */ public Class getSerializationView() { return _serializationView; } public JsonSerialize.Inclusion getSerializationInclusion() { if (_serializationInclusion != null) { return _serializationInclusion; } return isEnabled(Feature.WRITE_NULL_PROPERTIES) ? JsonSerialize.Inclusion.ALWAYS : JsonSerialize.Inclusion.NON_NULL; } /** * Method that will define global setting of which * bean/map properties are to be included in serialization. * Can be overridden by class annotations (overriding * settings to use for instances of that class) and * method/field annotations (overriding settings for the value * bean for that getter method or field) * * @deprecated since 1.9 should either use {@link #withSerializationInclusion} * to construct new instance, or configure through {@link ObjectMapper} */ @SuppressWarnings("deprecation") @Deprecated public void setSerializationInclusion(JsonSerialize.Inclusion props) { _serializationInclusion = props; // And for some level of backwards compatibility, also... if (props == JsonSerialize.Inclusion.NON_NULL) { disable(Feature.WRITE_NULL_PROPERTIES); } else { enable(Feature.WRITE_NULL_PROPERTIES); } } /** * Method for getting provider used for locating filters given * id (which is usually provided with filter annotations). * Will be null if no provided was set for {@link ObjectWriter} * (or if serialization directly called from {@link ObjectMapper}) * * @since 1.7 */ public FilterProvider getFilterProvider() { return _filterProvider; } /* /********************************************************** /* Introspection methods /********************************************************** */ /** * Method that will introspect full bean properties for the purpose * of building a bean serializer */ @SuppressWarnings("unchecked") public T introspect(JavaType type) { return (T) getClassIntrospector().forSerialization(this, type, this); } /* /********************************************************** /* Extended API: serializer instantiation /********************************************************** */ @SuppressWarnings("unchecked") public JsonSerializer serializerInstance(Annotated annotated, Class> serClass) { HandlerInstantiator hi = getHandlerInstantiator(); if (hi != null) { JsonSerializer ser = hi.serializerInstance(this, annotated, serClass); if (ser != null) { return (JsonSerializer) ser; } } return (JsonSerializer) ClassUtil.createInstance(serClass, canOverrideAccessModifiers()); } /* /********************************************************** /* Deprecated methods /********************************************************** */ /** * One thing to note is that this will set {@link Feature#WRITE_DATES_AS_TIMESTAMPS} * to false (if null format set), or true (if non-null format) * * @deprecated Since 1.8, use {@link #withDateFormat} instead. */ @SuppressWarnings("deprecation") @Override @Deprecated public final void setDateFormat(DateFormat df) { super.setDateFormat(df); set(Feature.WRITE_DATES_AS_TIMESTAMPS, (df == null)); } /** * Method for checking which serialization view is being used, * if any; null if none. * * @since 1.4 * * @deprecated Since 1.8, use {@link #withView} instead */ @Deprecated public void setSerializationView(Class view) { _serializationView = view; } /* /********************************************************** /* Debug support /********************************************************** */ @Override public String toString() { return "[SerializationConfig: flags=0x"+Integer.toHexString(_featureFlags)+"]"; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/SerializerFactory.java0000644000175000017500000001544711655120726030521 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.map.ser.BeanSerializerModifier; import org.codehaus.jackson.type.JavaType; /** * Abstract class that defines API used by {@link SerializerProvider} * to obtain actual * {@link JsonSerializer} instances from multiple distinct factories. */ public abstract class SerializerFactory { /* /********************************************************** /* Helper class to contain configuration settings /********************************************************** */ /** * Configuration settings container class for bean serializer factory. * * @since 1.7 */ public abstract static class Config { /** * Method for creating a new instance with additional serializer provider. */ public abstract Config withAdditionalSerializers(Serializers additional); /** * @since 1.8 */ public abstract Config withAdditionalKeySerializers(Serializers additional); /** * Method for creating a new instance with additional bean serializer modifier. */ public abstract Config withSerializerModifier(BeanSerializerModifier modifier); public abstract boolean hasSerializers(); public abstract boolean hasKeySerializers(); public abstract boolean hasSerializerModifiers(); public abstract Iterable serializers(); public abstract Iterable keySerializers(); public abstract Iterable serializerModifiers(); } /* /********************************************************** /* Additional configuration /********************************************************** */ /** * @since 1.7 */ public abstract Config getConfig(); /** * Method used for creating a new instance of this factory, but with different * configuration. Reason for specifying factory method (instead of plain constructor) * is to allow proper sub-classing of factories. *

* Note that custom sub-classes generally must override implementation * of this method, as it usually requires instantiating a new instance of * factory type. Check out javadocs for * {@link org.codehaus.jackson.map.ser.BeanSerializerFactory} for more details. * * @since 1.7 */ public abstract SerializerFactory withConfig(Config config); /** * Convenience method for creating a new factory instance with additional serializer * provider; equivalent to calling *

     *   withConfig(getConfig().withAdditionalSerializers(additional));
     *
     * 
     * @since 1.7
     */
    public final SerializerFactory withAdditionalSerializers(Serializers additional) {
        return withConfig(getConfig().withAdditionalSerializers(additional));
    }

    /**
     * @since 1.8
     */
    public final SerializerFactory withAdditionalKeySerializers(Serializers additional) {
        return withConfig(getConfig().withAdditionalKeySerializers(additional));
    }
    
    /**
     * Convenience method for creating a new factory instance with additional bean
     * serializer modifier; equivalent to calling
     *
     *   withConfig(getConfig().withSerializerModifier(modifier));
     *
     * 
     * @since 1.7
     */
    public final SerializerFactory withSerializerModifier(BeanSerializerModifier modifier) {
        return withConfig(getConfig().withSerializerModifier(modifier));
    }
    
    /*
    /**********************************************************
    /* Basic SerializerFactory API:
    /**********************************************************
     */

    /**
      * Method called to create (or, for immutable serializers, reuse) a serializer for given type. 
      */
    public abstract JsonSerializer createSerializer(SerializationConfig config, JavaType baseType,
            BeanProperty property)
        throws JsonMappingException;
    
    /**
     * Method called to create a type information serializer for given base type,
     * if one is needed. If not needed (no polymorphic handling configured), should
     * return null.
     *
     * @param baseType Declared type to use as the base type for type information serializer
     * 
     * @return Type serializer to use for the base type, if one is needed; null if not.
     * 
     * @since 1.7
     */
    public abstract TypeSerializer createTypeSerializer(SerializationConfig config, JavaType baseType,
            BeanProperty property)
        throws JsonMappingException;

    /**
     * Method called to create serializer to use for serializing JSON property names (which must
     * be output as JsonToken.FIELD_NAME) for Map that has specified declared
     * key type, and is for specified property (or, if property is null, as root value)
     * 
     * @param config Serialization configuration in use
     * @param baseType Declared type for Map keys
     * @param property Property that contains Map being serialized; null when serializing root Map value.
     * 
     * @return Serializer to use, if factory knows it; null if not (in which case default serializer
     *   is to be used)
     *   
     * @since 1.8
     */
    public abstract JsonSerializer createKeySerializer(SerializationConfig config, JavaType baseType,
            BeanProperty property)
        throws JsonMappingException;
    
    /*
    /**********************************************************
    /* Deprecated (as of 1.7) SerializerFactory API:
    /**********************************************************
     */

    /**
     * Deprecated version of accessor for type id serializer: as of 1.7 one needs
     * to instead call version that passes property information through.
     * 
     * @since 1.5
     * 
     * @deprecated Since 1.7, call variant with more arguments
     */
    @Deprecated
    public final JsonSerializer createSerializer(JavaType type, SerializationConfig config) {
        try {
            return createSerializer(config, type, null);
        } catch (JsonMappingException e) { // not optimal but:
            throw new RuntimeJsonMappingException(e);
        }
    }
    
    /**
     * Deprecated version of accessor for type id serializer: as of 1.7 one needs
     * to instead call version that passes property information through.
     * 
     * @since 1.5
     * 
     * @deprecated Since 1.7, call variant with more arguments
     */
    @Deprecated
    public final TypeSerializer createTypeSerializer(JavaType baseType, SerializationConfig config) {
        try {
            return createTypeSerializer(config, baseType, null);
        } catch (JsonMappingException e) { // not optimal but:
            throw new RuntimeException(e);
        }
    }
}
jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/MapperConfig.java0000644000175000017500000012124511655120726027424 0ustar  jamespagejamespagepackage org.codehaus.jackson.map;

import java.text.DateFormat;
import java.util.HashMap;
import java.util.Map;

import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.introspect.Annotated;
import org.codehaus.jackson.map.introspect.VisibilityChecker;
import org.codehaus.jackson.map.jsontype.SubtypeResolver;
import org.codehaus.jackson.map.jsontype.TypeIdResolver;
import org.codehaus.jackson.map.jsontype.TypeResolverBuilder;
import org.codehaus.jackson.map.jsontype.impl.StdSubtypeResolver;
import org.codehaus.jackson.map.type.ClassKey;
import org.codehaus.jackson.map.type.TypeBindings;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.map.util.ClassUtil;
import org.codehaus.jackson.map.util.StdDateFormat;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;

/**
 * Interface that defines functionality accessible through both
 * serialization and deserialization configuration objects;
 * accessors to mode-independent configuration settings
 * and such.
 *

* As of version 1.9, the goal is to make this class eventually immutable. * Because of this, existing methods that allow changing state of this * instance are deprecated in favor of methods that create new instances * with different configuration ("fluent factories"). * One major remaining issue is that of handling mix-in annotations, which * still represent bit of mutable state. * * @since 1.2 -- major change in 1.8, changed from interface to * abstract class */ public abstract class MapperConfig> implements ClassIntrospector.MixInResolver { /* /********************************************************** /* Constants, default values /********************************************************** */ /** * This is the default {@link DateFormat} used unless overridden by * custom implementation. */ protected final static DateFormat DEFAULT_DATE_FORMAT = StdDateFormat.instance; /* /********************************************************** /* Simple immutable basic settings /********************************************************** */ /** * Immutable container object for simple configuration settings. *

* Note: ideally this would be final, but until we can eliminate * mutators, must keep it mutable. */ protected Base _base; /* /********************************************************** /* Mix-in annotations /********************************************************** */ /** * Mapping that defines how to apply mix-in annotations: key is * the type to received additional annotations, and value is the * type that has annotations to "mix in". *

* Annotations associated with the value classes will be used to * override annotations of the key class, associated with the * same field or method. They can be further masked by sub-classes: * you can think of it as injecting annotations between the target * class and its sub-classes (or interfaces) * * @since 1.2 */ protected HashMap> _mixInAnnotations; /** * Flag used to detect when a copy if mix-in annotations is * needed: set when current copy is shared, cleared when a * fresh copy is made * * @since 1.2 */ protected boolean _mixInAnnotationsShared; /* /********************************************************** /* "Late bound" settings /********************************************************** */ /** * Registered concrete subtypes that can be used instead of (or * in addition to) ones declared using annotations. * Unlike most other settings, it is not configured as early * as it is set, but rather only when a non-shared instance * is constructed by ObjectMapper (or -Reader * or -Writer) *

* Note: this is the only property left as non-final, to allow * lazy construction of the instance as necessary. * * @since 1.6 */ protected SubtypeResolver _subtypeResolver; /* /********************************************************** /* Life-cycle: constructors /********************************************************** */ protected MapperConfig(ClassIntrospector ci, AnnotationIntrospector ai, VisibilityChecker vc, SubtypeResolver str, PropertyNamingStrategy pns, TypeFactory tf, HandlerInstantiator hi) { _base = new Base(ci, ai, vc, pns, tf, null, DEFAULT_DATE_FORMAT, hi); _subtypeResolver = str; // by default, assumed to be shared; only cleared when explicit copy is made _mixInAnnotationsShared = true; } /** * Simple copy constructor * * @since 1.8 */ protected MapperConfig(MapperConfig src) { this(src, src._base, src._subtypeResolver); } /** * @since 1.8 */ protected MapperConfig(MapperConfig src, MapperConfig.Base base, SubtypeResolver str) { _base = base; _subtypeResolver = str; // by default, assumed to be shared; only cleared when explicit copy is made _mixInAnnotationsShared = true; _mixInAnnotations = src._mixInAnnotations; } /* /********************************************************** /* Life-cycle: factory methods /********************************************************** */ /** * Method that checks class annotations that the argument Object has, * and modifies settings of this configuration object accordingly, * similar to how those annotations would affect actual value classes * annotated with them, but with global scope. Note that not all * annotations have global significance, and thus only subset of * Jackson annotations will have any effect. * * @deprecated Since 1.9, it is preferably to explicitly configure * instances; this method also modifies existing instance which is * against immutable design goals of this class. */ @Deprecated public abstract void fromAnnotations(Class cls); /** * Method to use for constructing an instance that is not shared * between multiple operations but only used for a single one * (which may be this instance, if it is immutable; if not, a copy * is constructed with same settings) * * @since 1.8 */ public abstract T createUnshared(SubtypeResolver subtypeResolver); /** * Method for constructing and returning a new instance with different * {@link ClassIntrospector} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withClassIntrospector(ClassIntrospector ci); /** * Method for constructing and returning a new instance with different * {@link AnnotationIntrospector} to use (replacing old one). *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withAnnotationIntrospector(AnnotationIntrospector ai); /** * Method for constructing and returning a new instance with different * {@link VisibilityChecker} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withVisibilityChecker(VisibilityChecker vc); /** * Method for constructing and returning a new instance with different * minimal visibility level for specified property type *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.9 */ public abstract T withVisibility(JsonMethod forMethod, JsonAutoDetect.Visibility visibility); /** * Method for constructing and returning a new instance with different * {@link TypeResolverBuilder} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withTypeResolverBuilder(TypeResolverBuilder trb); /** * Method for constructing and returning a new instance with different * {@link SubtypeResolver} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withSubtypeResolver(SubtypeResolver str); /** * Method for constructing and returning a new instance with different * {@link PropertyNamingStrategy} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withPropertyNamingStrategy(PropertyNamingStrategy strategy); /** * Method for constructing and returning a new instance with different * {@link TypeFactory} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withTypeFactory(TypeFactory typeFactory); /** * Method for constructing and returning a new instance with different * {@link DateFormat} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withDateFormat(DateFormat df); /** * Method for constructing and returning a new instance with different * {@link HandlerInstantiator} * to use. *

* NOTE: make sure to register new instance with ObjectMapper * if directly calling this method. * * @since 1.8 */ public abstract T withHandlerInstantiator(HandlerInstantiator hi); /** * Method for constructing and returning a new instance with additional * {@link AnnotationIntrospector} inserted (as the highest priority one) * * @since 1.9 */ public abstract T withInsertedAnnotationIntrospector(AnnotationIntrospector introspector); /** * Method for constructing and returning a new instance with additional * {@link AnnotationIntrospector} appended (as the lowest priority one) * * @since 1.9 */ public abstract T withAppendedAnnotationIntrospector(AnnotationIntrospector introspector); /* /********************************************************** /* Configuration: simple features /********************************************************** */ /** * Method for checking whether given feature is enabled or not */ public abstract boolean isEnabled(ConfigFeature f); /** * Method for determining whether annotation processing is enabled or not * (default settings are typically that it is enabled; must explicitly disable). * * @return True if annotation processing is enabled; false if not * * @since 1.8 */ public abstract boolean isAnnotationProcessingEnabled(); /** * Accessor for determining whether it is ok to try to force override of access * modifiers to be able to get or set values of non-public Methods, Fields; * to invoke non-public Constructors, Methods; or to instantiate non-public * Classes. By default this is enabled, but on some platforms it needs to be * prevented since if this would violate security constraints and cause failures. * * @return True if access modifier overriding is allowed (and may be done for * any Field, Method, Constructor or Class); false to prevent any attempts * to override. * * @since 1.8 */ public abstract boolean canOverrideAccessModifiers(); /** * Accessor for checking whether default settings for property handling * indicate that properties should be alphabetically ordered or not. * * @since 1.9 */ public abstract boolean shouldSortPropertiesAlphabetically(); /* /********************************************************** /* Configuration: introspectors, mix-ins /********************************************************** */ public ClassIntrospector getClassIntrospector() { return _base.getClassIntrospector(); } /** * Method for getting {@link AnnotationIntrospector} configured * to introspect annotation values used for configuration. *

* Non-final since it is actually overridden by sub-classes (for now?) */ public AnnotationIntrospector getAnnotationIntrospector() { return _base.getAnnotationIntrospector(); } /** * Method for registering specified {@link AnnotationIntrospector} as the highest * priority introspector (will be chained with existing introspector(s) which * will be used as fallbacks for cases this introspector does not handle) * * @param introspector Annotation introspector to register. * * @since 1.7 * * @deprecated Since 1.9 use {@link #withInsertedAnnotationIntrospector(AnnotationIntrospector)} instead; * this method is deprecated as it changes state, preventing immutability of instances */ @Deprecated public final void insertAnnotationIntrospector(AnnotationIntrospector introspector) { _base = _base.withAnnotationIntrospector(AnnotationIntrospector.Pair.create(introspector, getAnnotationIntrospector())); } /** * Method for registering specified {@link AnnotationIntrospector} as the lowest * priority introspector, chained with existing introspector(s) and called * as fallback for cases not otherwise handled. * * @param introspector Annotation introspector to register. * * @since 1.7 * * @deprecated Since 1.9 use {@link #withAppendedAnnotationIntrospector(AnnotationIntrospector)} instead; * this method is deprecated as it changes state, preventing immutability of instances */ @Deprecated public final void appendAnnotationIntrospector(AnnotationIntrospector introspector) { _base = _base.withAnnotationIntrospector(AnnotationIntrospector.Pair.create(getAnnotationIntrospector(), introspector)); } /** * Accessor for object used for determining whether specific property elements * (method, constructors, fields) can be auto-detected based on * their visibility (access modifiers). Can be changed to allow * different minimum visibility levels for auto-detection. Note * that this is the global handler; individual types (classes) * can further override active checker used (using * {@link JsonAutoDetect} annotation) * * @since 1.5 */ public VisibilityChecker getDefaultVisibilityChecker() { return _base.getVisibilityChecker(); } /** * @since 1.8 */ public final PropertyNamingStrategy getPropertyNamingStrategy() { return _base.getPropertyNamingStrategy(); } /** * @since 1.8 */ public final HandlerInstantiator getHandlerInstantiator() { return _base.getHandlerInstantiator(); } /* /********************************************************** /* Configuration: mix-in annotations /********************************************************** */ /** * Method to use for defining mix-in annotations to use for augmenting * annotations that processable (serializable / deserializable) * classes have. * Mixing in is done when introspecting class annotations and properties. * Map passed contains keys that are target classes (ones to augment * with new annotation overrides), and values that are source classes * (have annotations to use for augmentation). * Annotations from source classes (and their supertypes) * will override * annotations that target classes (and their super-types) have. * * @since 1.2 */ public final void setMixInAnnotations(Map, Class> sourceMixins) { HashMap> mixins = null; if (sourceMixins != null && sourceMixins.size() > 0) { mixins = new HashMap>(sourceMixins.size()); for (Map.Entry,Class> en : sourceMixins.entrySet()) { mixins.put(new ClassKey(en.getKey()), en.getValue()); } } _mixInAnnotationsShared = false; _mixInAnnotations = mixins; } /** * Method to use for adding mix-in annotations to use for augmenting * specified class or interface. All annotations from * mixinSource are taken to override annotations * that target (or its supertypes) has. * * @since 1.2 * * @param target Class (or interface) whose annotations to effectively override * @param mixinSource Class (or interface) whose annotations are to * be "added" to target's annotations, overriding as necessary */ public final void addMixInAnnotations(Class target, Class mixinSource) { if (_mixInAnnotations == null) { _mixInAnnotationsShared = false; _mixInAnnotations = new HashMap>(); } else if (_mixInAnnotationsShared) { _mixInAnnotationsShared = false; _mixInAnnotations = new HashMap>(_mixInAnnotations); } _mixInAnnotations.put(new ClassKey(target), mixinSource); } // ClassIntrospector.MixInResolver impl: /** * Method that will check if there are "mix-in" classes (with mix-in * annotations) for given class * * @since 1.2 */ @Override public final Class findMixInClassFor(Class cls) { return (_mixInAnnotations == null) ? null : _mixInAnnotations.get(new ClassKey(cls)); } /** * @since 1.8.1 */ public final int mixInCount() { return (_mixInAnnotations == null) ? 0 : _mixInAnnotations.size(); } /* /********************************************************** /* Configuration: type and subtype handling /********************************************************** */ /** * Method called to locate a type info handler for types that do not have * one explicitly declared via annotations (or other configuration). * If such default handler is configured, it is returned; otherwise * null is returned. * * @since 1.5 */ public final TypeResolverBuilder getDefaultTyper(JavaType baseType) { return _base.getTypeResolverBuilder(); } /** * Accessor for object used for finding out all reachable subtypes * for supertypes; needed when a logical type name is used instead * of class name (or custom scheme). * * @since 1.6 */ public final SubtypeResolver getSubtypeResolver() { if (_subtypeResolver == null) { _subtypeResolver = new StdSubtypeResolver(); } return _subtypeResolver; } /** * @since 1.8 */ public final TypeFactory getTypeFactory() { return _base.getTypeFactory(); } /** * Helper method that will construct {@link JavaType} for given * raw class. * This is a simple short-cut for: *

     *    getTypeFactory().constructType(cls);
     *
* * @since 1.8 */ public final JavaType constructType(Class cls) { return getTypeFactory().constructType(cls, (TypeBindings) null); } /** * Helper method that will construct {@link JavaType} for given * type reference * This is a simple short-cut for: *
     *    getTypeFactory().constructType(valueTypeRef);
     *
* * @since 1.9 */ public final JavaType constructType(TypeReference valueTypeRef) { return getTypeFactory().constructType(valueTypeRef.getType(), (TypeBindings) null); } /** * @since 1.9.1 */ public JavaType constructSpecializedType(JavaType baseType, Class subclass) { return getTypeFactory().constructSpecializedType(baseType, subclass); } /* /********************************************************** /* Configuration: other /********************************************************** */ /** * Method for accessing currently configured (textual) date format * that will be used for reading or writing date values (in case * of writing, only if textual output is configured; not if dates * are to be serialized as time stamps). *

* Note that typically {@link DateFormat} instances are not thread-safe * (at least ones provided by JDK): * this means that calling code should clone format instance before * using it. *

* This method is usually only called by framework itself, since there * are convenience methods available via * {@link DeserializationContext} and {@link SerializerProvider} that * take care of cloning and thread-safe reuse. */ public final DateFormat getDateFormat() { return _base.getDateFormat(); } /** * Accessor for getting bean description that only contains class * annotations: useful if no getter/setter/creator information is needed. * * @since 1.7 */ @SuppressWarnings("unchecked") public DESC introspectClassAnnotations(Class cls) { return (DESC) introspectClassAnnotations(constructType(cls)); } /** * Accessor for getting bean description that only contains class * annotations: useful if no getter/setter/creator information is needed. * * @since 1.9 */ public abstract DESC introspectClassAnnotations(JavaType type); /** * Accessor for getting bean description that only contains immediate class * annotations: ones from the class, and its direct mix-in, if any, but * not from super types. * * @since 1.7 */ @SuppressWarnings("unchecked") public DESC introspectDirectClassAnnotations(Class cls) { return (DESC) introspectDirectClassAnnotations(constructType(cls)); } /** * Accessor for getting bean description that only contains immediate class * annotations: ones from the class, and its direct mix-in, if any, but * not from super types. */ public abstract DESC introspectDirectClassAnnotations(JavaType type); /* /********************************************************** /* Methods for instantiating handlers /********************************************************** */ /** * Method that can be called to obtain an instance of TypeIdResolver of * specified type. * * @since 1.8 */ public TypeResolverBuilder typeResolverBuilderInstance(Annotated annotated, Class> builderClass) { HandlerInstantiator hi = getHandlerInstantiator(); if (hi != null) { TypeResolverBuilder builder = hi.typeResolverBuilderInstance(this, annotated, builderClass); if (builder != null) { return builder; } } return (TypeResolverBuilder) ClassUtil.createInstance(builderClass, canOverrideAccessModifiers()); } /** * Method that can be called to obtain an instance of TypeIdResolver of * specified type. * * @since 1.8 */ public TypeIdResolver typeIdResolverInstance(Annotated annotated, Class resolverClass) { HandlerInstantiator hi = getHandlerInstantiator(); if (hi != null) { TypeIdResolver builder = hi.typeIdResolverInstance(this, annotated, resolverClass); if (builder != null) { return builder; } } return (TypeIdResolver) ClassUtil.createInstance(resolverClass, canOverrideAccessModifiers()); } /* /********************************************************** /* Deprecated methods /********************************************************** */ /** * Method for replacing existing annotation introspector(s) with specified * introspector. * Since this method modifies state of configuration object directly, its use * is not recommended. * * @deprecated Since 1.8, use either * {@link #withAnnotationIntrospector(AnnotationIntrospector)} or * Module API instead */ @Deprecated public final void setAnnotationIntrospector(AnnotationIntrospector ai) { _base = _base.withAnnotationIntrospector(ai); } /** * Method that will define specific date format to use for reading/writing * Date and Calendar values. * If null is passed, will use {@link StdDateFormat}. * Instance is used as is, without creating a clone. * Format object in use can be accessed using {@link #getDateFormat}. * * @deprecated As of version 1.8, it is preferable to call method in * {@link ObjectMapper} instead; or construct new instance with * {@link #withDateFormat(DateFormat)} */ @Deprecated public void setDateFormat(DateFormat df) { if (df == null) { df = StdDateFormat.instance; } _base = _base.withDateFormat(df); } /* /********************************************************** /* Helper interface used with simple on/off features /********************************************************** */ /** * Interface that actual Feature enumerations used by * {@link MapperConfig} implementations must implement. * Necessary since enums can not be extended using normal * inheritance, but can implement interfaces * * @since 1.9 */ public interface ConfigFeature { /** * Accessor for checking whether this feature is enabled by default. */ public boolean enabledByDefault(); /** * Returns bit mask for this feature instance */ public int getMask(); } /* /********************************************************** /* Helper class to contain basic state needed to implement /* MapperConfig. /********************************************************** */ /** * Immutable container class used to store simple configuration * settings. Since instances are fully immutable, instances can * be freely shared and used without synchronization. */ public static class Base { /* /********************************************************** /* Configuration settings; introspection, related /********************************************************** */ /** * Introspector used to figure out Bean properties needed for bean serialization * and deserialization. Overridable so that it is possible to change low-level * details of introspection, like adding new annotation types. */ protected final ClassIntrospector _classIntrospector; /** * Introspector used for accessing annotation value based configuration. */ protected final AnnotationIntrospector _annotationIntrospector; /** * Object used for determining whether specific property elements * (method, constructors, fields) can be auto-detected based on * their visibility (access modifiers). Can be changed to allow * different minimum visibility levels for auto-detection. Note * that this is the global handler; individual types (classes) * can further override active checker used (using * {@link JsonAutoDetect} annotation) * * @since 1.5 */ protected final VisibilityChecker _visibilityChecker; /** * Custom property naming strategy in use, if any. * * @since 1.8 */ protected final PropertyNamingStrategy _propertyNamingStrategy; /** * Specific factory used for creating {@link JavaType} instances; * needed to allow modules to add more custom type handling * (mostly to support types of non-Java JVM languages) */ protected final TypeFactory _typeFactory; /* /********************************************************** /* Configuration settings; type resolution /********************************************************** */ /** * Type information handler used for "untyped" values (ones declared * to have type Object.class) * * @since 1.5 */ protected final TypeResolverBuilder _typeResolverBuilder; /* /********************************************************** /* Configuration settings; other /********************************************************** */ /** * Custom date format to use for de-serialization. If specified, will be * used instead of {@link org.codehaus.jackson.map.util.StdDateFormat}. *

* Note that the configured format object will be cloned once per * deserialization process (first time it is needed) */ protected final DateFormat _dateFormat; /** * Object used for creating instances of handlers (serializers, deserializers, * type and type id resolvers), given class to instantiate. This is typically * used to do additional configuration (with dependency injection, for example) * beyond simply construction of instances; or to use alternative constructors. */ protected final HandlerInstantiator _handlerInstantiator; /* /********************************************************** /* Construction /********************************************************** */ public Base(ClassIntrospector ci, AnnotationIntrospector ai, VisibilityChecker vc, PropertyNamingStrategy pns, TypeFactory tf, TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi) { _classIntrospector = ci; _annotationIntrospector = ai; _visibilityChecker = vc; _propertyNamingStrategy = pns; _typeFactory = tf; _typeResolverBuilder = typer; _dateFormat = dateFormat; _handlerInstantiator = hi; } /* /********************************************************** /* Factory methods /********************************************************** */ public Base withClassIntrospector(ClassIntrospector ci) { return new Base(ci, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator); } public Base withAnnotationIntrospector(AnnotationIntrospector ai) { return new Base(_classIntrospector, ai, _visibilityChecker, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator); } public Base withInsertedAnnotationIntrospector(AnnotationIntrospector ai) { return withAnnotationIntrospector(AnnotationIntrospector.Pair.create(ai, _annotationIntrospector)); } public Base withAppendedAnnotationIntrospector(AnnotationIntrospector ai) { return withAnnotationIntrospector(AnnotationIntrospector.Pair.create(_annotationIntrospector, ai)); } public Base withVisibilityChecker(VisibilityChecker vc) { return new Base(_classIntrospector, _annotationIntrospector, vc, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator); } public Base withVisibility(JsonMethod forMethod, JsonAutoDetect.Visibility visibility) { return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker.withVisibility(forMethod, visibility), _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator); } public Base withPropertyNamingStrategy(PropertyNamingStrategy pns) { return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, pns, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator); } public Base withTypeFactory(TypeFactory tf) { return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, tf, _typeResolverBuilder, _dateFormat, _handlerInstantiator); } public Base withTypeResolverBuilder(TypeResolverBuilder typer) { return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory, typer, _dateFormat, _handlerInstantiator); } public Base withDateFormat(DateFormat df) { return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, df, _handlerInstantiator); } public Base withHandlerInstantiator(HandlerInstantiator hi) { return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, hi); } /* /********************************************************** /* API /********************************************************** */ public ClassIntrospector getClassIntrospector() { return _classIntrospector; } public AnnotationIntrospector getAnnotationIntrospector() { return _annotationIntrospector; } public VisibilityChecker getVisibilityChecker() { return _visibilityChecker; } public PropertyNamingStrategy getPropertyNamingStrategy() { return _propertyNamingStrategy; } public TypeFactory getTypeFactory() { return _typeFactory; } public TypeResolverBuilder getTypeResolverBuilder() { return _typeResolverBuilder; } public DateFormat getDateFormat() { return _dateFormat; } public HandlerInstantiator getHandlerInstantiator() { return _handlerInstantiator; } } /* /********************************************************** /* Basic extension; added to avoid having to change generic /* signature of MapperConfig /* /* NOTE: May be merge in MapperConfig for 2.0, depending /* on how much we value backwards compatibility /********************************************************** */ static abstract class Impl> extends MapperConfig { /** *

* Note: moved to base class in 1.9; was stored by sub-class earlier */ protected int _featureFlags; /* /********************************************************** /* Construction /********************************************************** */ protected Impl(ClassIntrospector ci, AnnotationIntrospector ai, VisibilityChecker vc, SubtypeResolver str, PropertyNamingStrategy pns, TypeFactory tf, HandlerInstantiator hi, int defaultFeatures) { super(ci, ai, vc, str, pns, tf, hi); _featureFlags = defaultFeatures; } protected Impl(Impl src) { super(src); _featureFlags = src._featureFlags; } protected Impl(Impl src, int features) { super(src); _featureFlags = features; } /** * @since 1.8 */ protected Impl(Impl src, MapperConfig.Base base, SubtypeResolver str) { super(src, base, str); _featureFlags = src._featureFlags; } /** * Method that calculates bit set (flags) of all features that * are enabled by default. */ static & MapperConfig.ConfigFeature> int collectFeatureDefaults(Class enumClass) { int flags = 0; for (F value : enumClass.getEnumConstants()) { if (value.enabledByDefault()) { flags |= value.getMask(); } } return flags; } /* /********************************************************** /* Additional fluent-factory methods /********************************************************** */ /** * Fluent factory method that will construct and return a new configuration * object instance with specified features enabled. * * @since 1.9 */ public abstract T with(CFG... features); /** * Fluent factory method that will construct and return a new configuration * object instance with specified features disabled. * * @since 1.9 */ public abstract T without(CFG... features); /* /********************************************************** /* Configuration: simple features /********************************************************** */ /* NOTE: this method was added in 1.9, but should be * removed from 2.0 -- overloads do not work nicely with * enums, so we better not try *

* Also note that we can NOT use type variable CFG here, because * non-generic base class had to use base type. * * @Deprecated */ @Override public boolean isEnabled(MapperConfig.ConfigFeature f) { return (_featureFlags & f.getMask()) != 0; } /* /********************************************************** /* Configuration: deprecated methods /********************************************************** */ /** * Method for enabling specified feature. * * @deprecated Since 1.9, it is preferable to use {@link #with} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated public void enable(CFG f) { _featureFlags |= f.getMask(); } /** * Method for disabling specified feature. * * @deprecated Since 1.9, it is preferable to use {@link #without} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated public void disable(CFG f) { _featureFlags &= ~f.getMask(); } /** * Method for enabling or disabling specified feature. * * @deprecated Since 1.9, it is preferable to use {@link #with} and * {@link #without} methods instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @SuppressWarnings("deprecation") @Deprecated public void set(CFG f, boolean state) { if (state) { enable(f); } else { disable(f); } } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/KeyDeserializer.java0000644000175000017500000000174111655120726030143 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import org.codehaus.jackson.*; /** * Abstract class that defines API used for deserializing JSON content * field names into Java Map keys. These deserializers are only used * if the Map key class is not String or Object. */ public abstract class KeyDeserializer { /** * Method called to deserialize a {@link java.util.Map} key from JSON property name. */ public abstract Object deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException; /** * This marker class is only to be used with annotations, to * indicate that no deserializer is configured. *

* Specifically, this class is to be used as the marker for * annotation {@link org.codehaus.jackson.map.annotate.JsonDeserialize}. * * @since 1.3 */ public abstract static class None extends KeyDeserializer { } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/RuntimeJsonMappingException.java0000644000175000017500000000104211655120726032512 0ustar jamespagejamespagepackage org.codehaus.jackson.map; /** * Wrapper used when interface does not allow throwing a checked * {@link JsonMappingException} */ @SuppressWarnings("serial") public class RuntimeJsonMappingException extends RuntimeException { public RuntimeJsonMappingException(JsonMappingException cause) { super(cause); } public RuntimeJsonMappingException(String message) { super(message); } public RuntimeJsonMappingException(String message, JsonMappingException cause) { super(message, cause); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/DeserializerFactory.java0000644000175000017500000003315311655120726031024 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.map.deser.BeanDeserializerModifier; import org.codehaus.jackson.map.deser.ValueInstantiator; import org.codehaus.jackson.map.deser.ValueInstantiators; import org.codehaus.jackson.map.introspect.BasicBeanDescription; import org.codehaus.jackson.map.type.*; import org.codehaus.jackson.type.JavaType; /** * Abstract class that defines API used by {@link DeserializerProvider} * to obtain actual * {@link JsonDeserializer} instances from multiple distinct factories. *

* Since there are multiple broad categories of deserializers, there are * multiple factory methods: *

    *
  • For JSON "Array" type, we need 2 methods: one to deal with expected * Java arrays ({@link #createArrayDeserializer}) * and the other for other Java containers like {@link java.util.List}s * and {@link java.util.Set}s ({@link #createCollectionDeserializer(DeserializationConfig, DeserializerProvider, CollectionType, BeanProperty)}) *
  • *
  • For JSON "Object" type, we need 2 methods: one to deal with * expected Java {@link java.util.Map}s * ({@link #createMapDeserializer}), and another for POJOs * ({@link #createBeanDeserializer(DeserializationConfig, DeserializerProvider, JavaType, BeanProperty)}. *
  • *
  • For Tree Model ({@link org.codehaus.jackson.JsonNode}) properties there is * {@link #createTreeDeserializer(DeserializationConfig, DeserializerProvider, JavaType, BeanProperty)} *
  • For enumerated types ({@link java.lang.Enum}) there is * {@link #createEnumDeserializer(DeserializationConfig, DeserializerProvider, JavaType, BeanProperty)} *
  • *
  • For all other types, {@link #createBeanDeserializer(DeserializationConfig, DeserializerProvider, JavaType, BeanProperty)} * is used. *
*

* All above methods take 2 type arguments, except for the first one * which takes just a single argument. */ public abstract class DeserializerFactory { protected final static Deserializers[] NO_DESERIALIZERS = new Deserializers[0]; /* /********************************************************** /* Helper class to contain configuration settings /********************************************************** */ /** * Configuration settings container class for bean deserializer factory * * @since 1.7 */ public abstract static class Config { /** * Fluent/factory method used to construct a configuration object that * has same deserializer providers as this instance, plus one specified * as argument. Additional provider will be added before existing ones, * meaning it has priority over existing definitions. */ public abstract Config withAdditionalDeserializers(Deserializers additional); /** * Fluent/factory method used to construct a configuration object that * has same key deserializer providers as this instance, plus one specified * as argument. Additional provider will be added before existing ones, * meaning it has priority over existing definitions. */ public abstract Config withAdditionalKeyDeserializers(KeyDeserializers additional); /** * Fluent/factory method used to construct a configuration object that * has same configuration as this instance plus one additional * deserialiazer modifier. Added modifier has the highest priority (that is, it * gets called before any already registered modifier). */ public abstract Config withDeserializerModifier(BeanDeserializerModifier modifier); /** * Fluent/factory method used to construct a configuration object that * has same configuration as this instance plus one additional * abstract type resolver. * Added resolver has the highest priority (that is, it * gets called before any already registered resolver). * * @since 1.8 */ public abstract Config withAbstractTypeResolver(AbstractTypeResolver resolver); /** * Fluent/factory method used to construct a configuration object that * has same configuration as this instance plus specified additional * value instantiator provider object. * Added instantiator provider has the highest priority (that is, it * gets called before any already registered resolver). * * @param instantiators Object that can provide {@link org.codehaus.jackson.map.deser.ValueInstantiator}s for * constructing POJO values during deserialization * * @since 1.9 */ public abstract Config withValueInstantiators(ValueInstantiators instantiators); public abstract Iterable deserializers(); /** * @since 1.8 */ public abstract Iterable keyDeserializers(); public abstract Iterable deserializerModifiers(); /** * @since 1.8 */ public abstract Iterable abstractTypeResolvers(); /** * @since 1.9 */ public abstract Iterable valueInstantiators(); public abstract boolean hasDeserializers(); /** * @since 1.8 */ public abstract boolean hasKeyDeserializers(); public abstract boolean hasDeserializerModifiers(); /** * @since 1.8 */ public abstract boolean hasAbstractTypeResolvers(); /** * @since 1.9 */ public abstract boolean hasValueInstantiators(); } /* /******************************************************** /* Configuration handling /******************************************************** */ /** * @since 1.7 */ public abstract Config getConfig(); /** * Method used for creating a new instance of this factory, but with different * configuration. Reason for specifying factory method (instead of plain constructor) * is to allow proper sub-classing of factories. *

* Note that custom sub-classes must override implementation * of this method, as it usually requires instantiating a new instance of * factory type. Check out javadocs for * {@link org.codehaus.jackson.map.deser.BeanDeserializerFactory} for more details. * * @since 1.7 */ public abstract DeserializerFactory withConfig(Config config); /** * Convenience method for creating a new factory instance with additional deserializer * provider. * * @since 1.7 */ public final DeserializerFactory withAdditionalDeserializers(Deserializers additional) { return withConfig(getConfig().withAdditionalDeserializers(additional)); } /** * Convenience method for creating a new factory instance with additional * {@link KeyDeserializers}. * * @since 1.8 */ public final DeserializerFactory withAdditionalKeyDeserializers(KeyDeserializers additional) { return withConfig(getConfig().withAdditionalKeyDeserializers(additional)); } /** * Convenience method for creating a new factory instance with additional * {@link BeanDeserializerModifier}. * * @since 1.7 */ public final DeserializerFactory withDeserializerModifier(BeanDeserializerModifier modifier) { return withConfig(getConfig().withDeserializerModifier(modifier)); } /** * Convenience method for creating a new factory instance with additional * {@link AbstractTypeResolver}. * * @since 1.7 */ public final DeserializerFactory withAbstractTypeResolver(AbstractTypeResolver resolver) { return withConfig(getConfig().withAbstractTypeResolver(resolver)); } /** * Convenience method for creating a new factory instance with additional * {@link ValueInstantiators}. * * @since 1.9 */ public final DeserializerFactory withValueInstantiators(ValueInstantiators instantiators) { return withConfig(getConfig().withValueInstantiators(instantiators)); } /* /********************************************************** /* Basic DeserializerFactory API: /********************************************************** */ /** * Method that can be called to try to resolve an abstract type * (interface, abstract class) into a concrete type, or at least * something "more concrete" (abstract class instead of interface). * Will either return passed type, or a more specific type. * * @since 1.9 */ public abstract JavaType mapAbstractType(DeserializationConfig config, JavaType type) throws JsonMappingException; /** * Method that is to find all creators (constructors, factory methods) * for the bean type to deserialize. * * @since 1.9 */ public abstract ValueInstantiator findValueInstantiator(DeserializationConfig config, BasicBeanDescription beanDesc) throws JsonMappingException; /** * Method called to create (or, for completely immutable deserializers, * reuse) a deserializer that can convert JSON content into values of * specified Java "bean" (POJO) type. * At this point it is known that the type is not otherwise recognized * as one of structured types (array, Collection, Map) or a well-known * JDK type (enum, primitives/wrappers, String); this method only * gets called if other options are exhausted. This also means that * this method can be overridden to add support for custom types. * * @param type Type to be deserialized * @param p Provider that can be called to create deserializers for * contained member types */ public abstract JsonDeserializer createBeanDeserializer(DeserializationConfig config, DeserializerProvider p, JavaType type, BeanProperty property) throws JsonMappingException; /** * Method called to create (or, for completely immutable deserializers, * reuse) a deserializer that can convert JSON content into values of * specified Java type. * * @param type Type to be deserialized * @param p Provider that can be called to create deserializers for * contained member types */ public abstract JsonDeserializer createArrayDeserializer(DeserializationConfig config, DeserializerProvider p, ArrayType type, BeanProperty property) throws JsonMappingException; public abstract JsonDeserializer createCollectionDeserializer(DeserializationConfig config, DeserializerProvider p, CollectionType type, BeanProperty property) throws JsonMappingException; /** * @since 1.8 */ public abstract JsonDeserializer createCollectionLikeDeserializer(DeserializationConfig config, DeserializerProvider p, CollectionLikeType type, BeanProperty property) throws JsonMappingException; public abstract JsonDeserializer createEnumDeserializer(DeserializationConfig config, DeserializerProvider p, JavaType type, BeanProperty property) throws JsonMappingException; public abstract JsonDeserializer createMapDeserializer(DeserializationConfig config, DeserializerProvider p, MapType type, BeanProperty property) throws JsonMappingException; /** * @since 1.8 */ public abstract JsonDeserializer createMapLikeDeserializer(DeserializationConfig config, DeserializerProvider p, MapLikeType type, BeanProperty property) throws JsonMappingException; /** * Method called to create and return a deserializer that can construct * JsonNode(s) from JSON content. */ public abstract JsonDeserializer createTreeDeserializer(DeserializationConfig config, DeserializerProvider p, JavaType type, BeanProperty property) throws JsonMappingException; /** * Method called to find if factory knows how to create a key deserializer * for specified type; currently this means checking if a module has registered * possible deserializers. * * @return Key deserializer to use for specified type, if one found; null if not * (and default key deserializer should be used) * * @since 1.8 */ public KeyDeserializer createKeyDeserializer(DeserializationConfig config, JavaType type, BeanProperty property) throws JsonMappingException { // Default implementation returns null for backwards compatibility reasons return null; } /** * Method called to find and create a type information deserializer for given base type, * if one is needed. If not needed (no polymorphic handling configured for type), * should return null. *

* Note that this method is usually only directly called for values of container (Collection, * array, Map) types and root values, but not for bean property values. * * @param baseType Declared base type of the value to deserializer (actual * deserializer type will be this type or its subtype) * * @return Type deserializer to use for given base type, if one is needed; null if not. * * @since 1.5 */ public TypeDeserializer findTypeDeserializer(DeserializationConfig config, JavaType baseType, BeanProperty property) throws JsonMappingException { // Default implementation returns null for backwards compatibility reasons return null; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ObjectWriter.java0000644000175000017500000004324411655120726027457 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.*; import java.text.DateFormat; import org.codehaus.jackson.*; import org.codehaus.jackson.io.SegmentedStringWriter; import org.codehaus.jackson.map.ser.FilterProvider; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.TypeReference; import org.codehaus.jackson.util.ByteArrayBuilder; import org.codehaus.jackson.util.DefaultPrettyPrinter; import org.codehaus.jackson.util.MinimalPrettyPrinter; import org.codehaus.jackson.util.VersionUtil; /** * Builder object that can be used for per-serialization configuration of * serialization parameters, such as JSON View and root type to use. * (and thus fully thread-safe with no external synchronization); * new instances are constructed for different configurations. * Instances are initially constructed by {@link ObjectMapper} and can be * reused in completely thread-safe manner with no explicit synchronization * * @author tatu * @since 1.5 */ public class ObjectWriter implements Versioned // since 1.6 { /** * We need to keep track of explicit disabling of pretty printing; * easiest to do by a token value. */ protected final static PrettyPrinter NULL_PRETTY_PRINTER = new MinimalPrettyPrinter(); /* /********************************************************** /* Immutable configuration from ObjectMapper /********************************************************** */ /** * General serialization configuration settings */ protected final SerializationConfig _config; protected final SerializerProvider _provider; protected final SerializerFactory _serializerFactory; /** * Factory used for constructing {@link JsonGenerator}s */ protected final JsonFactory _jsonFactory; /* /********************************************************** /* Configuration that can be changed during building /********************************************************** */ /** * Specified root serialization type to use; can be same * as runtime type, but usually one of its super types */ protected final JavaType _rootType; /** * To allow for dynamic enabling/disabling of pretty printing, * pretty printer can be optionally configured for writer * as well */ protected final PrettyPrinter _prettyPrinter; /** * When using data format that uses a schema, schema is passed * to generator. * * @since 1.8 */ protected final FormatSchema _schema; /* /********************************************************** /* Life-cycle, constructors /********************************************************** */ /** * Constructor used by {@link ObjectMapper} for initial instantiation */ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config, JavaType rootType, PrettyPrinter pp) { _config = config; _provider = mapper._serializerProvider; _serializerFactory = mapper._serializerFactory; _jsonFactory = mapper._jsonFactory; _rootType = rootType; _prettyPrinter = pp; _schema = null; } /** * Alternative constructor for initial instantiation. * * @since 1.7 */ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config) { _config = config; _provider = mapper._serializerProvider; _serializerFactory = mapper._serializerFactory; _jsonFactory = mapper._jsonFactory; _rootType = null; _prettyPrinter = null; _schema = null; } /** * Alternative constructor for initial instantiation. * * @since 1.7 */ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config, FormatSchema s) { _config = config; _provider = mapper._serializerProvider; _serializerFactory = mapper._serializerFactory; _jsonFactory = mapper._jsonFactory; _rootType = null; _prettyPrinter = null; _schema = s; } /** * Copy constructor used for building variations. */ protected ObjectWriter(ObjectWriter base, SerializationConfig config, JavaType rootType, PrettyPrinter pp, FormatSchema s) { _config = config; _provider = base._provider; _serializerFactory = base._serializerFactory; _jsonFactory = base._jsonFactory; _rootType = rootType; _prettyPrinter = pp; _schema = s; } /** * Copy constructor used for building variations. * * @since 1.7 */ protected ObjectWriter(ObjectWriter base, SerializationConfig config) { _config = config; _provider = base._provider; _serializerFactory = base._serializerFactory; _jsonFactory = base._jsonFactory; _schema = base._schema; _rootType = base._rootType; _prettyPrinter = base._prettyPrinter; } /** * Method that will return version information stored in and read from jar * that contains this class. * * @since 1.6 */ @Override public Version version() { return VersionUtil.versionFor(getClass()); } /* /********************************************************** /* Life-cycle, fluent factories /********************************************************** */ /** * Method that will construct a new instance that uses specified * serialization view for serialization (with null basically disables * view processing) */ public ObjectWriter withView(Class view) { if (view == _config.getSerializationView()) return this; return new ObjectWriter(this, _config.withView(view)); } /** * Method that will construct a new instance that uses specific type * as the root type for serialization, instead of runtime dynamic * type of the root object itself. */ public ObjectWriter withType(JavaType rootType) { if (rootType == _rootType) return this; // type is stored here, no need to make a copy of config return new ObjectWriter(this, _config, rootType, _prettyPrinter, _schema); } /** * Method that will construct a new instance that uses specific type * as the root type for serialization, instead of runtime dynamic * type of the root object itself. */ public ObjectWriter withType(Class rootType) { return withType(_config.constructType(rootType)); } /** * @since 1.7 */ public ObjectWriter withType(TypeReference rootType) { return withType(_config.getTypeFactory().constructType(rootType.getType())); } /** * Method that will construct a new instance that will use specified pretty * printer (or, if null, will not do any pretty-printing) * * @since 1.6 */ public ObjectWriter withPrettyPrinter(PrettyPrinter pp) { if (pp == _prettyPrinter) { return this; } // since null would mean "don't care", need to use placeholder to indicate "disable" if (pp == null) { pp = NULL_PRETTY_PRINTER; } return new ObjectWriter(this, _config, _rootType, pp, _schema); } /** * Method that will construct a new instance that will use the default * pretty printer for serialization. * * @since 1.6 */ public ObjectWriter withDefaultPrettyPrinter() { return withPrettyPrinter(new DefaultPrettyPrinter()); } /** * Method that will construct a new instance that uses specified * provider for resolving filter instances by id. * * @since 1.7 */ public ObjectWriter withFilters(FilterProvider filterProvider) { if (filterProvider == _config.getFilterProvider()) { // no change? return this; } return new ObjectWriter(this, _config.withFilters(filterProvider)); } /** * @since 1.8 */ public ObjectWriter withSchema(FormatSchema schema) { if (_schema == schema) { return this; } return new ObjectWriter(this, _config, _rootType, _prettyPrinter, schema); } /** * Fluent factory method that will construct a new writer instance that will * use specified date format for serializing dates; or if null passed, one * that will serialize dates as numeric timestamps. * * @since 1.9 */ public ObjectWriter withDateFormat(DateFormat df) { SerializationConfig newConfig = _config.withDateFormat(df); if (newConfig == _config) { return this; } return new ObjectWriter(this, newConfig); } /* /********************************************************** /* Serialization methods; ones from ObjectCodec first /********************************************************** */ /** * Method that can be used to serialize any Java value as * JSON output, using provided {@link JsonGenerator}. */ public void writeValue(JsonGenerator jgen, Object value) throws IOException, JsonGenerationException, JsonMappingException { if (_config.isEnabled(SerializationConfig.Feature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) { _writeCloseableValue(jgen, value, _config); } else { if (_rootType == null) { _provider.serializeValue(_config, jgen, value, _serializerFactory); } else { _provider.serializeValue(_config, jgen, value, _rootType, _serializerFactory); } if (_config.isEnabled(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE)) { jgen.flush(); } } } /* /********************************************************** /* Serialization methods, others /********************************************************** */ /** * Method that can be used to serialize any Java value as * JSON output, written to File provided. */ public void writeValue(File resultFile, Object value) throws IOException, JsonGenerationException, JsonMappingException { _configAndWriteValue(_jsonFactory.createJsonGenerator(resultFile, JsonEncoding.UTF8), value); } /** * Method that can be used to serialize any Java value as * JSON output, using output stream provided (using encoding * {@link JsonEncoding#UTF8}). *

* Note: method does not close the underlying stream explicitly * here; however, {@link JsonFactory} this mapper uses may choose * to close the stream depending on its settings (by default, * it will try to close it when {@link JsonGenerator} we construct * is closed). */ public void writeValue(OutputStream out, Object value) throws IOException, JsonGenerationException, JsonMappingException { _configAndWriteValue(_jsonFactory.createJsonGenerator(out, JsonEncoding.UTF8), value); } /** * Method that can be used to serialize any Java value as * JSON output, using Writer provided. *

* Note: method does not close the underlying stream explicitly * here; however, {@link JsonFactory} this mapper uses may choose * to close the stream depending on its settings (by default, * it will try to close it when {@link JsonGenerator} we construct * is closed). */ public void writeValue(Writer w, Object value) throws IOException, JsonGenerationException, JsonMappingException { _configAndWriteValue(_jsonFactory.createJsonGenerator(w), value); } /** * Method that can be used to serialize any Java value as * a String. Functionally equivalent to calling * {@link #writeValue(Writer,Object)} with {@link java.io.StringWriter} * and constructing String, but more efficient. */ public String writeValueAsString(Object value) throws IOException, JsonGenerationException, JsonMappingException { // alas, we have to pull the recycler directly here... SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler()); _configAndWriteValue(_jsonFactory.createJsonGenerator(sw), value); return sw.getAndClear(); } /** * Method that can be used to serialize any Java value as * a byte array. Functionally equivalent to calling * {@link #writeValue(Writer,Object)} with {@link java.io.ByteArrayOutputStream} * and getting bytes, but more efficient. * Encoding used will be UTF-8. */ public byte[] writeValueAsBytes(Object value) throws IOException, JsonGenerationException, JsonMappingException { ByteArrayBuilder bb = new ByteArrayBuilder(_jsonFactory._getBufferRecycler()); _configAndWriteValue(_jsonFactory.createJsonGenerator(bb, JsonEncoding.UTF8), value); byte[] result = bb.toByteArray(); bb.release(); return result; } /* /********************************************************** /* Other public methods /********************************************************** */ public boolean canSerialize(Class type) { return _provider.hasSerializerFor(_config, type, _serializerFactory); } /* /********************************************************** /* Internal methods /********************************************************** */ /** * Method called to configure the generator as necessary and then * call write functionality */ protected final void _configAndWriteValue(JsonGenerator jgen, Object value) throws IOException, JsonGenerationException, JsonMappingException { if (_prettyPrinter != null) { PrettyPrinter pp = _prettyPrinter; jgen.setPrettyPrinter((pp == NULL_PRETTY_PRINTER) ? null : pp); } else if (_config.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) { jgen.useDefaultPrettyPrinter(); } // [JACKSON-520]: add support for pass-through schema: if (_schema != null) { jgen.setSchema(_schema); } // [JACKSON-282]: consider Closeable if (_config.isEnabled(SerializationConfig.Feature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) { _configAndWriteCloseable(jgen, value, _config); return; } boolean closed = false; try { if (_rootType == null) { _provider.serializeValue(_config, jgen, value, _serializerFactory); } else { _provider.serializeValue(_config, jgen, value, _rootType, _serializerFactory); } closed = true; jgen.close(); } finally { /* won't try to close twice; also, must catch exception (so it * will not mask exception that is pending) */ if (!closed) { try { jgen.close(); } catch (IOException ioe) { } } } } /** * Helper method used when value to serialize is {@link Closeable} and its close() * method is to be called right after serialization has been called */ private final void _configAndWriteCloseable(JsonGenerator jgen, Object value, SerializationConfig cfg) throws IOException, JsonGenerationException, JsonMappingException { Closeable toClose = (Closeable) value; try { if (_rootType == null) { _provider.serializeValue(cfg, jgen, value, _serializerFactory); } else { _provider.serializeValue(cfg, jgen, value, _rootType, _serializerFactory); } // [JACKSON-520]: add support for pass-through schema: if (_schema != null) { jgen.setSchema(_schema); } JsonGenerator tmpJgen = jgen; jgen = null; tmpJgen.close(); Closeable tmpToClose = toClose; toClose = null; tmpToClose.close(); } finally { /* Need to close both generator and value, as long as they haven't yet * been closed */ if (jgen != null) { try { jgen.close(); } catch (IOException ioe) { } } if (toClose != null) { try { toClose.close(); } catch (IOException ioe) { } } } } /** * Helper method used when value to serialize is {@link Closeable} and its close() * method is to be called right after serialization has been called */ private final void _writeCloseableValue(JsonGenerator jgen, Object value, SerializationConfig cfg) throws IOException, JsonGenerationException, JsonMappingException { Closeable toClose = (Closeable) value; try { if (_rootType == null) { _provider.serializeValue(cfg, jgen, value, _serializerFactory); } else { _provider.serializeValue(cfg, jgen, value, _rootType, _serializerFactory); } if (_config.isEnabled(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE)) { jgen.flush(); } Closeable tmpToClose = toClose; toClose = null; tmpToClose.close(); } finally { if (toClose != null) { try { toClose.close(); } catch (IOException ioe) { } } } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/MappingIterator.java0000644000175000017500000000723611655120726030162 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import java.util.*; import org.codehaus.jackson.*; import org.codehaus.jackson.type.JavaType; /** * Iterator exposed by {@link ObjectMapper} when binding sequence of * objects. Extension is done to allow more convenient exposing of * {@link IOException} (which basic {@link Iterator} does not expose) * * @since 1.8 */ public class MappingIterator implements Iterator { protected final static MappingIterator EMPTY_ITERATOR = new MappingIterator(null, null, null, null); protected final JavaType _type; protected final DeserializationContext _context; protected final JsonDeserializer _deserializer; protected final JsonParser _parser; @SuppressWarnings("unchecked") protected MappingIterator(JavaType type, JsonParser jp, DeserializationContext ctxt, JsonDeserializer deser) { _type = type; _parser = jp; _context = ctxt; _deserializer = (JsonDeserializer) deser; /* One more thing: if we are at START_ARRAY (but NOT root-level * one!), advance to next token (to allow matching END_ARRAY) */ if (jp != null && jp.getCurrentToken() == JsonToken.START_ARRAY) { JsonStreamContext sc = jp.getParsingContext(); // safest way to skip current token is to clear it (so we'll advance soon) if (!sc.inRoot()) { jp.clearCurrentToken(); } } } @SuppressWarnings("unchecked") protected static MappingIterator emptyIterator() { return (MappingIterator) EMPTY_ITERATOR; } /* /********************************************************** /* Basic iterator impl /********************************************************** */ @Override public boolean hasNext() { try { return hasNextValue(); } catch (JsonMappingException e) { throw new RuntimeJsonMappingException(e.getMessage(), e); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } } @Override public T next() { try { return nextValue(); } catch (JsonMappingException e) { throw new RuntimeJsonMappingException(e.getMessage(), e); } catch (IOException e) { throw new RuntimeException(e.getMessage(), e); } } @Override public void remove() { throw new UnsupportedOperationException(); } /* /********************************************************** /* Extended API /********************************************************** */ /** * Equivalent of {@link #next} but one that may throw checked * exceptions from Jackson due to invalid input. */ public boolean hasNextValue() throws IOException { if (_parser == null) { return false; } JsonToken t = _parser.getCurrentToken(); if (t == null) { // un-initialized or cleared; find next t = _parser.nextToken(); // If EOF, no more if (t == null) { _parser.close(); return false; } // And similarly if we hit END_ARRAY; except that we won't close parser if (t == JsonToken.END_ARRAY) { return false; } } return true; } public T nextValue() throws IOException { T result = _deserializer.deserialize(_parser, _context); // Need to consume the token too _parser.clearCurrentToken(); return result; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/0000755000175000017500000000000011672662540025006 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/CoreXMLSerializers.java0000644000175000017500000000524111655120726031335 0ustar jamespagejamespagepackage org.codehaus.jackson.map.ext; import java.io.IOException; import java.lang.reflect.Type; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.xml.datatype.Duration; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.ser.std.CalendarSerializer; import org.codehaus.jackson.map.ser.std.SerializerBase; import org.codehaus.jackson.map.ser.std.ToStringSerializer; import org.codehaus.jackson.map.util.Provider; /** * Provider for serializers of XML types that are part of full JDK 1.5, but * that some alleged 1.5 platforms are missing (Android, GAE). * And for this reason these are added using more dynamic mechanism. *

* Note: since many of classes defined are abstract, caller must take * care not to just use straight equivalency check but rather consider * subclassing as well. * * @since 1.4 */ public class CoreXMLSerializers implements Provider,JsonSerializer>> { final static HashMap,JsonSerializer> _serializers = new HashMap,JsonSerializer>(); /** * We will construct instances statically, during class loading, to try to * make things fail-fast, i.e. to catch problems as soon as possible. */ static { ToStringSerializer tss = ToStringSerializer.instance; _serializers.put(Duration.class, tss); _serializers.put(XMLGregorianCalendar.class, new XMLGregorianCalendarSerializer()); _serializers.put(QName.class, tss); } @Override public Collection,JsonSerializer>> provide() { return _serializers.entrySet(); } public static class XMLGregorianCalendarSerializer extends SerializerBase { public XMLGregorianCalendarSerializer() { super(XMLGregorianCalendar.class); } @Override public void serialize(XMLGregorianCalendar value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { CalendarSerializer.instance.serialize(value.toGregorianCalendar(), jgen, provider); } @Override public JsonNode getSchema(SerializerProvider provider, Type typeHint) throws JsonMappingException { return CalendarSerializer.instance.getSchema(provider, typeHint); } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/JodaDeserializers.java0000644000175000017500000002274011655120726031255 0ustar jamespagejamespagepackage org.codehaus.jackson.map.ext; import java.io.IOException; import java.util.*; import org.joda.time.*; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.deser.std.StdDeserializer; import org.codehaus.jackson.map.deser.std.StdScalarDeserializer; import org.codehaus.jackson.map.util.Provider; /** * Provider for deserializers that handle some basic data types * for Joda date/time library. * * @since 1.4 */ public class JodaDeserializers implements Provider> { @Override public Collection> provide() { return Arrays.asList(new StdDeserializer[] { new DateTimeDeserializer(DateTime.class) ,new DateTimeDeserializer(ReadableDateTime.class) ,new DateTimeDeserializer(ReadableInstant.class) ,new LocalDateDeserializer() ,new LocalDateTimeDeserializer() ,new DateMidnightDeserializer() ,new PeriodDeserializer() }); } /* /********************************************************************* /* Intermediate base classes /********************************************************************* */ abstract static class JodaDeserializer extends StdScalarDeserializer { final static DateTimeFormatter _localDateTimeFormat = ISODateTimeFormat.localDateOptionalTimeParser(); protected JodaDeserializer(Class cls) { super(cls); } protected DateTime parseLocal(JsonParser jp) throws IOException, JsonProcessingException { String str = jp.getText().trim(); if (str.length() == 0) { // [JACKSON-360] return null; } return _localDateTimeFormat.parseDateTime(str); } } /* /********************************************************************* /* Concrete deserializers /********************************************************************* */ /** * Basic deserializer for {@link DateTime}. Accepts JSON String and Number * values and passes those to single-argument constructor. * Does not (yet?) support JSON object; support can be added if desired. *

* Since 1.6 this has been generic, to handle multiple related types, * including super types of {@link DateTime} */ public static class DateTimeDeserializer extends JodaDeserializer { public DateTimeDeserializer(Class cls) { super(cls); } @SuppressWarnings("unchecked") @Override public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonToken t = jp.getCurrentToken(); if (t == JsonToken.VALUE_NUMBER_INT) { return (T) new DateTime(jp.getLongValue(), DateTimeZone.UTC); } if (t == JsonToken.VALUE_STRING) { String str = jp.getText().trim(); if (str.length() == 0) { // [JACKSON-360] return null; } return (T) new DateTime(str, DateTimeZone.UTC); } throw ctxt.mappingException(getValueClass()); } } /** * @since 1.5 */ public static class LocalDateDeserializer extends JodaDeserializer { public LocalDateDeserializer() { super(LocalDate.class); } @Override public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // We'll accept either long (timestamp) or array: if (jp.isExpectedStartArrayToken()) { jp.nextToken(); // VALUE_NUMBER_INT int year = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int month = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int day = jp.getIntValue(); if (jp.nextToken() != JsonToken.END_ARRAY) { throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalDate ints"); } return new LocalDate(year, month, day); } switch (jp.getCurrentToken()) { case VALUE_NUMBER_INT: return new LocalDate(jp.getLongValue()); case VALUE_STRING: DateTime local = parseLocal(jp); if (local == null) { return null; } return local.toLocalDate(); } throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array, String or Number"); } } /** * @since 1.5 */ public static class LocalDateTimeDeserializer extends JodaDeserializer { public LocalDateTimeDeserializer() { super(LocalDateTime.class); } @Override public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // We'll accept either long (timestamp) or array: if (jp.isExpectedStartArrayToken()) { jp.nextToken(); // VALUE_NUMBER_INT int year = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int month = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int day = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int hour = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int minute = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int second = jp.getIntValue(); // let's leave milliseconds optional? int millisecond = 0; if (jp.nextToken() != JsonToken.END_ARRAY) { // VALUE_NUMBER_INT millisecond = jp.getIntValue(); jp.nextToken(); // END_ARRAY? } if (jp.getCurrentToken() != JsonToken.END_ARRAY) { throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalDateTime ints"); } return new LocalDateTime(year, month, day, hour, minute, second, millisecond); } switch (jp.getCurrentToken()) { case VALUE_NUMBER_INT: return new LocalDateTime(jp.getLongValue()); case VALUE_STRING: DateTime local = parseLocal(jp); if (local == null) { return null; } return local.toLocalDateTime(); } throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array or Number"); } } /** * @since 1.5 */ public static class DateMidnightDeserializer extends JodaDeserializer { public DateMidnightDeserializer() { super(DateMidnight.class); } @Override public DateMidnight deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // We'll accept either long (timestamp) or array: if (jp.isExpectedStartArrayToken()) { jp.nextToken(); // VALUE_NUMBER_INT int year = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int month = jp.getIntValue(); jp.nextToken(); // VALUE_NUMBER_INT int day = jp.getIntValue(); if (jp.nextToken() != JsonToken.END_ARRAY) { throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after DateMidnight ints"); } return new DateMidnight(year, month, day); } switch (jp.getCurrentToken()) { case VALUE_NUMBER_INT: return new DateMidnight(jp.getLongValue()); case VALUE_STRING: DateTime local = parseLocal(jp); if (local == null) { return null; } return local.toDateMidnight(); } throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array, Number or String"); } } /** * @since 1.9.2 */ public static class PeriodDeserializer extends JodaDeserializer { public PeriodDeserializer() { super(ReadablePeriod.class); } @Override public ReadablePeriod deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // TODO: perhaps support array of numbers... //if (jp.isExpectedStartArrayToken()) { ] switch (jp.getCurrentToken()) { case VALUE_NUMBER_INT: // assume it's millisecond count return new Period(jp.getLongValue()); case VALUE_STRING: return new Period(jp.getText()); } throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Number or String"); } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/OptionalHandlerFactory.java0000644000175000017500000002031211655120726032256 0ustar jamespagejamespagepackage org.codehaus.jackson.map.ext; import java.util.Collection; import java.util.Map; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.deser.std.StdDeserializer; import org.codehaus.jackson.map.util.Provider; import org.codehaus.jackson.type.JavaType; /** * Helper class used for isolating details of handling optional+external types (Joda datetime, * javax.xml classes) from standard factories that offer them. * * @author tatu * * @since 1.6.1 */ public class OptionalHandlerFactory { /* 1.6.1+ To make 2 main "optional" handler groups (javax.xml.stream, Joda date/time) * more dynamic, we better only figure out handlers completely dynamically, if and * when they are needed. To do this we need to assume package prefixes. */ private final static String PACKAGE_PREFIX_JODA_DATETIME = "org.joda.time."; private final static String PACKAGE_PREFIX_JAVAX_XML = "javax.xml."; private final static String SERIALIZERS_FOR_JODA_DATETIME = "org.codehaus.jackson.map.ext.JodaSerializers"; private final static String SERIALIZERS_FOR_JAVAX_XML = "org.codehaus.jackson.map.ext.CoreXMLSerializers"; private final static String DESERIALIZERS_FOR_JODA_DATETIME = "org.codehaus.jackson.map.ext.JodaDeserializers"; private final static String DESERIALIZERS_FOR_JAVAX_XML = "org.codehaus.jackson.map.ext.CoreXMLDeserializers"; // Plus we also have a single serializer for DOM Node: private final static String CLASS_NAME_DOM_NODE = "org.w3c.dom.Node"; private final static String CLASS_NAME_DOM_DOCUMENT = "org.w3c.dom.Node"; private final static String SERIALIZER_FOR_DOM_NODE = "org.codehaus.jackson.map.ext.DOMSerializer"; private final static String DESERIALIZER_FOR_DOM_DOCUMENT = "org.codehaus.jackson.map.ext.DOMDeserializer$DocumentDeserializer"; private final static String DESERIALIZER_FOR_DOM_NODE = "org.codehaus.jackson.map.ext.DOMDeserializer$NodeDeserializer"; public final static OptionalHandlerFactory instance = new OptionalHandlerFactory(); protected OptionalHandlerFactory() { } /* /********************************************************** /* Public API /********************************************************** */ public JsonSerializer findSerializer(SerializationConfig config, JavaType type) // BasicBeanDescription beanInfo, BeanProperty property) { Class rawType = type.getRawClass(); String className = rawType.getName(); String factoryName; if (className.startsWith(PACKAGE_PREFIX_JODA_DATETIME)) { factoryName = SERIALIZERS_FOR_JODA_DATETIME; } else if (className.startsWith(PACKAGE_PREFIX_JAVAX_XML) || hasSupertypeStartingWith(rawType, PACKAGE_PREFIX_JAVAX_XML)) { factoryName = SERIALIZERS_FOR_JAVAX_XML; } else if (doesImplement(rawType, CLASS_NAME_DOM_NODE)) { return (JsonSerializer) instantiate(SERIALIZER_FOR_DOM_NODE); } else { return null; } Object ob = instantiate(factoryName); if (ob == null) { // could warn, if we had logging system (j.u.l?) return null; } @SuppressWarnings("unchecked") Provider,JsonSerializer>> prov = (Provider,JsonSerializer>>) ob; Collection,JsonSerializer>> entries = prov.provide(); // first, check for exact match (concrete) for (Map.Entry,JsonSerializer> entry : entries) { if (rawType == entry.getKey()) { return entry.getValue(); } } // if no match, check super-type match for (Map.Entry,JsonSerializer> entry : entries) { if (entry.getKey().isAssignableFrom(rawType)) { return entry.getValue(); } } // but maybe there's just no match to be found? return null; } public JsonDeserializer findDeserializer(JavaType type, DeserializationConfig config, DeserializerProvider p) { Class rawType = type.getRawClass(); String className = rawType.getName(); String factoryName; if (className.startsWith(PACKAGE_PREFIX_JODA_DATETIME)) { factoryName = DESERIALIZERS_FOR_JODA_DATETIME; } else if (className.startsWith(PACKAGE_PREFIX_JAVAX_XML) || hasSupertypeStartingWith(rawType, PACKAGE_PREFIX_JAVAX_XML)) { factoryName = DESERIALIZERS_FOR_JAVAX_XML; } else if (doesImplement(rawType, CLASS_NAME_DOM_DOCUMENT)) { return (JsonDeserializer) instantiate(DESERIALIZER_FOR_DOM_DOCUMENT); } else if (doesImplement(rawType, CLASS_NAME_DOM_NODE)) { return (JsonDeserializer) instantiate(DESERIALIZER_FOR_DOM_NODE); } else { return null; } Object ob = instantiate(factoryName); if (ob == null) { // could warn, if we had logging system (j.u.l?) return null; } @SuppressWarnings("unchecked") Provider> prov = (Provider>) ob; Collection> entries = prov.provide(); // first, check for exact match (concrete) for (StdDeserializer deser : entries) { if (rawType == deser.getValueClass()) { return deser; } } // if no match, check super-type match for (StdDeserializer deser : entries) { if (deser.getValueClass().isAssignableFrom(rawType)) { return deser; } } // but maybe there's just no match to be found? return null; } /* /********************************************************** /* Internal helper methods /********************************************************** */ private Object instantiate(String className) { try { return Class.forName(className).newInstance(); } catch (LinkageError e) { } // too many different kinds to enumerate here: catch (Exception e) { } return null; } private boolean doesImplement(Class actualType, String classNameToImplement) { for (Class type = actualType; type != null; type = type.getSuperclass()) { if (type.getName().equals(classNameToImplement)) { return true; } // or maybe one of super-interfaces if (hasInterface(type, classNameToImplement)) { return true; } } return false; } private boolean hasInterface(Class type, String interfaceToImplement) { Class[] interfaces = type.getInterfaces(); for (Class iface : interfaces) { if (iface.getName().equals(interfaceToImplement)) { return true; } } // maybe super-interface? for (Class iface : interfaces) { if (hasInterface(iface, interfaceToImplement)) { return true; } } return false; } private boolean hasSupertypeStartingWith(Class rawType, String prefix) { // first, superclasses for (Class supertype = rawType.getSuperclass(); supertype != null; supertype = supertype.getSuperclass()) { if (supertype.getName().startsWith(prefix)) { return true; } } // then interfaces for (Class cls = rawType; cls != null; cls = cls.getSuperclass()) { if (hasInterfaceStartingWith(cls, prefix)) { return true; } } return false; } private boolean hasInterfaceStartingWith(Class type, String prefix) { Class[] interfaces = type.getInterfaces(); for (Class iface : interfaces) { if (iface.getName().startsWith(prefix)) { return true; } } // maybe super-interface? for (Class iface : interfaces) { if (hasInterfaceStartingWith(iface, prefix)) { return true; } } return false; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/DOMDeserializer.java0000644000175000017500000000421111655120726030625 0ustar jamespagejamespagepackage org.codehaus.jackson.map.ext; import java.io.StringReader; import javax.xml.parsers.DocumentBuilderFactory; import org.codehaus.jackson.map.DeserializationContext; import org.codehaus.jackson.map.deser.std.FromStringDeserializer; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; /** * Base for serializers that allows parsing DOM Documents from JSON Strings. * Nominal type can be either {@link org.w3c.dom.Node} or * {@link org.w3c.dom.Document}. */ public abstract class DOMDeserializer extends FromStringDeserializer { final static DocumentBuilderFactory _parserFactory; static { _parserFactory = DocumentBuilderFactory.newInstance(); // yup, only cave men do XML without recognizing namespaces... _parserFactory.setNamespaceAware(true); } protected DOMDeserializer(Class cls) { super(cls); } @Override public abstract T _deserialize(String value, DeserializationContext ctxt); protected final Document parse(String value) throws IllegalArgumentException { try { return _parserFactory.newDocumentBuilder().parse(new InputSource(new StringReader(value))); } catch (Exception e) { throw new IllegalArgumentException("Failed to parse JSON String as XML: "+e.getMessage(), e); } } /* /********************************************************** /* Concrete deserializers /********************************************************** */ public static class NodeDeserializer extends DOMDeserializer { public NodeDeserializer() { super(Node.class); } @Override public Node _deserialize(String value, DeserializationContext ctxt) throws IllegalArgumentException { return parse(value); } } public static class DocumentDeserializer extends DOMDeserializer { public DocumentDeserializer() { super(Document.class); } @Override public Document _deserialize(String value, DeserializationContext ctxt) throws IllegalArgumentException { return parse(value); } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/package-info.java0000644000175000017500000000145511655120726030176 0ustar jamespagejamespage/** Contains extended support for "external" packages: things that may or may not be present in runtime environment, but that are commonly enough used so that explicit support can be added.

Currently supported extensions include:

  • Support for Java 1.5 core XML datatypes: the reason these are considered "external" is that some platforms that claim to be 1.5 conformant are only partially so (Google Android, GAE) and do not included these types.
  • Joda time. This package has superior date/time handling functionality, and is thus supported. However, to minimize forced dependencies this support is added as extension so that Joda is not needed by Jackson itself: but if it is present, its core types are supported to some degree
*/ package org.codehaus.jackson.map.ext; jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/CoreXMLDeserializers.java0000644000175000017500000000722711655120726031654 0ustar jamespagejamespagepackage org.codehaus.jackson.map.ext; import java.io.IOException; import java.util.*; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.map.DeserializationContext; import org.codehaus.jackson.map.deser.std.StdDeserializer; import org.codehaus.jackson.map.deser.std.FromStringDeserializer; import org.codehaus.jackson.map.deser.std.StdScalarDeserializer; import org.codehaus.jackson.map.util.Provider; /** * Container deserializers that handle "core" XML types: ones included in standard * JDK 1.5. Types are directly needed by JAXB, and are thus supported within core * mapper package, not in "xc" package. * * @since 1.3 */ public class CoreXMLDeserializers implements Provider> { /** * Data type factories are thread-safe after instantiation (and * configuration, if any); and since instantion (esp. implementation * introspection) can be expensive we better reuse the instance. */ final static DatatypeFactory _dataTypeFactory; static { try { _dataTypeFactory = DatatypeFactory.newInstance(); } catch (DatatypeConfigurationException e) { throw new RuntimeException(e); } } /* /********************************************************** /* Provider implementation /********************************************************** */ /** * Method called by {@link org.codehaus.jackson.map.deser.BasicDeserializerFactory} * to register deserializers this class provides. */ @Override public Collection> provide() { return Arrays.asList(new StdDeserializer[] { new DurationDeserializer() ,new GregorianCalendarDeserializer() ,new QNameDeserializer() }); } /* /********************************************************** /* Concrete deserializers /********************************************************** */ public static class DurationDeserializer extends FromStringDeserializer { public DurationDeserializer() { super(Duration.class); } @Override protected Duration _deserialize(String value, DeserializationContext ctxt) throws IllegalArgumentException { return _dataTypeFactory.newDuration(value); } } public static class GregorianCalendarDeserializer extends StdScalarDeserializer { public GregorianCalendarDeserializer() { super(XMLGregorianCalendar.class); } @Override public XMLGregorianCalendar deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { Date d = _parseDate(jp, ctxt); if (d == null) { return null; } GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(d); return _dataTypeFactory.newXMLGregorianCalendar(calendar); } } public static class QNameDeserializer extends FromStringDeserializer { public QNameDeserializer() { super(QName.class); } @Override protected QName _deserialize(String value, DeserializationContext ctxt) throws IllegalArgumentException { return QName.valueOf(value); } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/JodaSerializers.java0000644000175000017500000001661111655120726030744 0ustar jamespagejamespagepackage org.codehaus.jackson.map.ext; import java.io.IOException; import java.util.*; import org.joda.time.*; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.ser.std.SerializerBase; import org.codehaus.jackson.map.ser.std.ToStringSerializer; import org.codehaus.jackson.map.util.Provider; /** * Provider for serializers that handle some basic data types * for Joda date/time library. *

* Since version 1.5, more types are supported. These types use slightly * different approach to serialization than core date types: "timestamp" * notation is implemented using JSON arrays, for improved readability. * * @since 1.4 */ public class JodaSerializers implements Provider,JsonSerializer>> { final static HashMap,JsonSerializer> _serializers = new HashMap,JsonSerializer>(); static { _serializers.put(DateTime.class, new DateTimeSerializer()); _serializers.put(LocalDateTime.class, new LocalDateTimeSerializer()); _serializers.put(LocalDate.class, new LocalDateSerializer()); _serializers.put(DateMidnight.class, new DateMidnightSerializer()); // [JACKSON-706]: _serializers.put(Period.class, ToStringSerializer.instance); } public JodaSerializers() { } @Override public Collection,JsonSerializer>> provide() { return _serializers.entrySet(); } /* /********************************************************** /* Intermediate base classes /********************************************************** */ protected abstract static class JodaSerializer extends SerializerBase { final static DateTimeFormatter _localDateTimeFormat = ISODateTimeFormat.dateTime(); final static DateTimeFormatter _localDateFormat = ISODateTimeFormat.date(); protected JodaSerializer(Class cls) { super(cls); } protected String printLocalDateTime(ReadablePartial dateValue) throws IOException, JsonProcessingException { return _localDateTimeFormat.print(dateValue); } protected String printLocalDate(ReadablePartial dateValue) throws IOException, JsonProcessingException { return _localDateFormat.print(dateValue); } protected String printLocalDate(ReadableInstant dateValue) throws IOException, JsonProcessingException { return _localDateFormat.print(dateValue); } } /* /********************************************************** /* Concrete serializers /********************************************************** */ public final static class DateTimeSerializer extends JodaSerializer { public DateTimeSerializer() { super(DateTime.class); } @Override public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { if (provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)) { jgen.writeNumber(value.getMillis()); } else { jgen.writeString(value.toString()); } } @Override public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) { return createSchemaNode(provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS) ? "number" : "string", true); } } /** * * @since 1.5 */ public final static class LocalDateTimeSerializer extends JodaSerializer { public LocalDateTimeSerializer() { super(LocalDateTime.class); } @Override public void serialize(LocalDateTime dt, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { if (provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)) { // Timestamp here actually means an array of values jgen.writeStartArray(); jgen.writeNumber(dt.year().get()); jgen.writeNumber(dt.monthOfYear().get()); jgen.writeNumber(dt.dayOfMonth().get()); jgen.writeNumber(dt.hourOfDay().get()); jgen.writeNumber(dt.minuteOfHour().get()); jgen.writeNumber(dt.secondOfMinute().get()); jgen.writeNumber(dt.millisOfSecond().get()); jgen.writeEndArray(); } else { jgen.writeString(printLocalDateTime(dt)); } } @Override public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) { return createSchemaNode(provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS) ? "array" : "string", true); } } public final static class LocalDateSerializer extends JodaSerializer { public LocalDateSerializer() { super(LocalDate.class); } @Override public void serialize(LocalDate dt, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { if (provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)) { // Timestamp here actually means an array of values jgen.writeStartArray(); jgen.writeNumber(dt.year().get()); jgen.writeNumber(dt.monthOfYear().get()); jgen.writeNumber(dt.dayOfMonth().get()); jgen.writeEndArray(); } else { jgen.writeString(printLocalDate(dt)); } } @Override public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) { return createSchemaNode(provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS) ? "array" : "string", true); } } public final static class DateMidnightSerializer extends JodaSerializer { public DateMidnightSerializer() { super(DateMidnight.class); } @Override public void serialize(DateMidnight dt, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { if (provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)) { // same as with other date-only values jgen.writeStartArray(); jgen.writeNumber(dt.year().get()); jgen.writeNumber(dt.monthOfYear().get()); jgen.writeNumber(dt.dayOfMonth().get()); jgen.writeEndArray(); } else { jgen.writeString(printLocalDate(dt)); } } @Override public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) { return createSchemaNode(provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS) ? "array" : "string", true); } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ext/DOMSerializer.java0000644000175000017500000000310511655120726030315 0ustar jamespagejamespagepackage org.codehaus.jackson.map.ext; import java.io.IOException; import org.w3c.dom.Node; import org.w3c.dom.bootstrap.DOMImplementationRegistry; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSSerializer; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.SerializerProvider; import org.codehaus.jackson.map.ser.std.SerializerBase; public class DOMSerializer extends SerializerBase { protected final DOMImplementationLS _domImpl; public DOMSerializer() { super(Node.class); DOMImplementationRegistry registry; try { registry = DOMImplementationRegistry.newInstance(); } catch (Exception e) { throw new IllegalStateException("Could not instantiate DOMImplementationRegistry: "+e.getMessage(), e); } _domImpl = (DOMImplementationLS)registry.getDOMImplementation("LS"); } @Override public void serialize(Node value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { if (_domImpl == null) throw new IllegalStateException("Could not find DOM LS"); LSSerializer writer = _domImpl.createLSSerializer(); jgen.writeString(writer.writeToString(value)); } @Override public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) { // Well... it is serialized as String return createSchemaNode("string", true); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/DeserializationProblemHandler.java0000644000175000017500000000431511655120726033015 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import org.codehaus.jackson.JsonProcessingException; /** * This is the class that can be registered (via * {@link DeserializationConfig} object owner by * {@link ObjectMapper}) to get calledn when a potentially * recoverable problem is encountered during deserialization * process. Handlers can try to resolve the problem, throw * an exception or do nothing. *

* Default implementations for all methods implemented minimal * "do nothing" functionality, which is roughly equivalent to * not having a registered listener at all. This allows for * only implemented handler methods one is interested in, without * handling other cases. * * @author tatu */ public abstract class DeserializationProblemHandler { /** * Method called when a Json Map ("Object") entry with an unrecognized * name is encountered. * Content (supposedly) matching the property are accessible via * parser that can be obtained from passed deserialization context. * Handler can also choose to skip the content; if so, it MUST return * true to indicate it did handle property succesfully. * Skipping is usually done like so: *

     *  ctxt.getParser().skipChildren();
     *
*

* Note: version 1.2 added new deserialization feature * (DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES). * It will only have effect after handler is called, and only * if handler did not handle the problem. * * @param beanOrClass Either bean instance being deserialized (if one * has been instantiated so far); or Class that indicates type that * will be instantiated (if no instantiation done yet: for example * when bean uses non-default constructors) * * @return True if the problem was succesfully resolved (and content available * used or skipped); false if listen */ public boolean handleUnknownProperty(DeserializationContext ctxt, JsonDeserializer deserializer, Object beanOrClass, String propertyName) throws IOException, JsonProcessingException { return false; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/0000755000175000017500000000000011672662540025473 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/SimpleValueInstantiators.java0000644000175000017500000000271111655120726033344 0ustar jamespagejamespagepackage org.codehaus.jackson.map.module; import java.util.HashMap; import org.codehaus.jackson.map.BeanDescription; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.deser.ValueInstantiator; import org.codehaus.jackson.map.deser.ValueInstantiators; import org.codehaus.jackson.map.type.ClassKey; public class SimpleValueInstantiators extends ValueInstantiators.Base { /** * Mappings from raw (type-erased, i.e. non-generic) types * to matching {@link ValueInstantiator} instances. */ protected HashMap _classMappings; /* /********************************************************** /* Life-cycle, construction and configuring /********************************************************** */ public SimpleValueInstantiators() { _classMappings = new HashMap(); } public SimpleValueInstantiators addValueInstantiator(Class forType, ValueInstantiator inst) { _classMappings.put(new ClassKey(forType), inst); return this; } @Override public ValueInstantiator findValueInstantiator(DeserializationConfig config, BeanDescription beanDesc, ValueInstantiator defaultInstantiator) { ValueInstantiator inst = _classMappings.get(new ClassKey(beanDesc.getBeanClass())); return (inst == null) ? defaultInstantiator : inst; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/SimpleKeyDeserializers.java0000644000175000017500000000360611655120726032767 0ustar jamespagejamespagepackage org.codehaus.jackson.map.module; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.type.ClassKey; import org.codehaus.jackson.type.JavaType; /** * Simple implementation {@link KeyDeserializers} which allows registration of * deserializers based on raw (type erased class). * It can work well for basic bean and scalar type deserializers, but is not * a good fit for handling generic types (like {@link Map}s and {@link Collection}s * or array types). *

* Unlike {@link SimpleSerializers}, this class does not currently support generic mappings; * all mappings must be to exact declared deserialization type. * * @since 1.7 */ public class SimpleKeyDeserializers implements KeyDeserializers { protected HashMap _classMappings = null; /* /********************************************************** /* Life-cycle, construction and configuring /********************************************************** */ public SimpleKeyDeserializers() { } public SimpleKeyDeserializers addDeserializer(Class forClass, KeyDeserializer deser) { if (_classMappings == null) { _classMappings = new HashMap(); } _classMappings.put(new ClassKey(forClass), deser); return this; } /* /********************************************************** /* Serializers implementation /********************************************************** */ @Override public KeyDeserializer findKeyDeserializer(JavaType type, DeserializationConfig config, BeanDescription beanDesc, BeanProperty property) { if (_classMappings == null) { return null; } return _classMappings.get(new ClassKey(type.getRawClass())); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/SimpleAbstractTypeResolver.java0000644000175000017500000000637611655120726033647 0ustar jamespagejamespagepackage org.codehaus.jackson.map.module; import java.lang.reflect.Modifier; import java.util.*; import org.codehaus.jackson.map.AbstractTypeResolver; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.type.ClassKey; import org.codehaus.jackson.type.JavaType; /** * Simple {@link AbstractTypeResolver} implementation, which is * based on static mapping from abstract super types into * sub types (concrete or abstract), but retaining generic * parameterization. * Can be used for things like specifying which implementation of * {@link java.util.Collection} to use: *

 *  SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver();
 *  // To make all properties declared as Collection, List, to LinkedList
 *  resolver.addMapping(Collection.class, LinkedList.class);
 *  resolver.addMapping(List.class, LinkedList.class);
 *
* Can also be used as an alternative to per-class annotations when defining * concrete implementations; however, only works with abstract types (since * this is only called for abstract types) * * @since 1.8 */ public class SimpleAbstractTypeResolver extends AbstractTypeResolver { /** * Mappings from super types to subtypes */ protected final HashMap> _mappings = new HashMap>(); /** * Method for adding a mapping from super type to specific subtype. * Arguments will be checked by method, to ensure that superType * is abstract (since resolver is never called for concrete classes); * as well as to ensure that there is supertype/subtype relationship * (to ensure there won't be cycles during resolution). * * @param superType Abstract type to resolve * @param subType Sub-class of superType, to map superTo to * * @return This resolver, to allow chaining of initializations */ public SimpleAbstractTypeResolver addMapping(Class superType, Class subType) { // Sanity checks, just in case someone tries to force typing... if (superType == subType) { throw new IllegalArgumentException("Can not add mapping from class to itself"); } if (!superType.isAssignableFrom(subType)) { throw new IllegalArgumentException("Can not add mapping from class "+superType.getName() +" to "+subType.getName()+", as latter is not a subtype of former"); } if (!Modifier.isAbstract(superType.getModifiers())) { throw new IllegalArgumentException("Can not add mapping from class "+superType.getName() +" since it is not abstract"); } _mappings.put(new ClassKey(superType), subType); return this; } @Override public JavaType findTypeMapping(DeserializationConfig config, JavaType type) { // this is the main mapping base, so let's Class src = type.getRawClass(); Class dst = _mappings.get(new ClassKey(src)); if (dst == null) { return null; } return type.narrowBy(dst); } @Override public JavaType resolveAbstractType(DeserializationConfig config, JavaType type) { // never materialize anything, so: return null; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/package-info.java0000644000175000017500000000122011655120726030651 0ustar jamespagejamespage/** * Package that contains classes and interfaces to help implement * custom extension {@link org.codehaus.jackson.map.Module}s * (which are registered using * {@link org.codehaus.jackson.map.ObjectMapper#registerModule}. *

* Note that classes in the package only support registering * handlers for non-generic types (types without type * parameterization) -- hence "simple" -- which works for * many cases, but not all. So if you will need to register * handlers for generic types, you will usually need to either * sub-class handlers, or implement/extend base types directly. * * @since 1.7 */ package org.codehaus.jackson.map.module; jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/SimpleDeserializers.java0000644000175000017500000001170211655120726032312 0ustar jamespagejamespagepackage org.codehaus.jackson.map.module; import java.util.*; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.type.*; import org.codehaus.jackson.type.JavaType; /** * Simple implementation {@link Deserializers} which allows registration of * deserializers based on raw (type erased class). * It can work well for basic bean and scalar type deserializers, but is not * a good fit for handling generic types (like {@link Map}s and {@link Collection}s * or array types). *

* Unlike {@link SimpleSerializers}, this class does not currently support generic mappings; * all mappings must be to exact declared deserialization type. * * @since 1.7 */ public class SimpleDeserializers implements Deserializers { protected HashMap> _classMappings = null; /* /********************************************************** /* Life-cycle, construction and configuring /********************************************************** */ public SimpleDeserializers() { } public void addDeserializer(Class forClass, JsonDeserializer deser) { ClassKey key = new ClassKey(forClass); if (_classMappings == null) { _classMappings = new HashMap>(); } _classMappings.put(key, deser); } /* /********************************************************** /* Serializers implementation /********************************************************** */ @Override public JsonDeserializer findArrayDeserializer(ArrayType type, DeserializationConfig config, DeserializerProvider provider, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(type.getRawClass())); } @Override public JsonDeserializer findBeanDeserializer(JavaType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(type.getRawClass())); } @Override public JsonDeserializer findCollectionDeserializer(CollectionType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(type.getRawClass())); } @Override public JsonDeserializer findCollectionLikeDeserializer(CollectionLikeType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(type.getRawClass())); } @Override public JsonDeserializer findEnumDeserializer(Class type, DeserializationConfig config, BeanDescription beanDesc, BeanProperty property) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(type)); } @Override public JsonDeserializer findMapDeserializer(MapType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(type.getRawClass())); } @Override public JsonDeserializer findMapLikeDeserializer(MapLikeType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(type.getRawClass())); } @Override public JsonDeserializer findTreeNodeDeserializer(Class nodeType, DeserializationConfig config, BeanProperty property) throws JsonMappingException { return (_classMappings == null) ? null : _classMappings.get(new ClassKey(nodeType)); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/SimpleSerializers.java0000644000175000017500000001707211655120726032007 0ustar jamespagejamespagepackage org.codehaus.jackson.map.module; import java.util.*; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.type.ArrayType; import org.codehaus.jackson.map.type.ClassKey; import org.codehaus.jackson.map.type.CollectionLikeType; import org.codehaus.jackson.map.type.CollectionType; import org.codehaus.jackson.map.type.MapLikeType; import org.codehaus.jackson.map.type.MapType; import org.codehaus.jackson.type.JavaType; /** * Simple implementation {@link Serializers} which allows registration of * serializers based on raw (type erased class). * It can work well for basic bean and scalar type serializers, but is not * a good fit for handling generic types (like {@link Map}s and {@link Collection}s). *

* Type registrations are assumed to be general; meaning that registration of serializer * for a super type will also be used for handling subtypes, unless an exact match * is found first. As an example, handler for {@link CharSequence} would also be used * serializing {@link StringBuilder} instances, unless a direct mapping was found. * * @since 1.7 */ public class SimpleSerializers extends Serializers.Base { /** * Class-based mappings that are used both for exact and * sub-class matches. */ protected HashMap> _classMappings = null; /** * Interface-based matches. */ protected HashMap> _interfaceMappings = null; /* /********************************************************** /* Life-cycle, construction and configuring /********************************************************** */ public SimpleSerializers() { } /** * Method for adding given serializer for type that {@link JsonSerializer#handledType} * specifies (which MUST return a non-null class; and can NOT be {@link Object}, as a * sanity check). * For serializers that do not declare handled type, use the variant that takes * two arguments. * * @param ser */ public void addSerializer(JsonSerializer ser) { // Interface to match? Class cls = ser.handledType(); if (cls == null || cls == Object.class) { throw new IllegalArgumentException("JsonSerializer of type "+ser.getClass().getName() +" does not define valid handledType() -- must either register with method that takes type argument " +" or make serializer extend 'org.codehaus.jackson.map.ser.std.SerializerBase'"); } _addSerializer(cls, ser); } public void addSerializer(Class type, JsonSerializer ser) { _addSerializer(type, ser); } private void _addSerializer(Class cls, JsonSerializer ser) { ClassKey key = new ClassKey(cls); // Interface or class type? if (cls.isInterface()) { if (_interfaceMappings == null) { _interfaceMappings = new HashMap>(); } _interfaceMappings.put(key, ser); } else { // nope, class: if (_classMappings == null) { _classMappings = new HashMap>(); } _classMappings.put(key, ser); } } /* /********************************************************** /* Serializers implementation /********************************************************** */ @Override public JsonSerializer findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc, BeanProperty property) { Class cls = type.getRawClass(); ClassKey key = new ClassKey(cls); JsonSerializer ser = null; // First: direct match? if (cls.isInterface()) { if (_interfaceMappings != null) { ser = _interfaceMappings.get(key); if (ser != null) { return ser; } } } else { if (_classMappings != null) { ser = _classMappings.get(key); if (ser != null) { return ser; } // If not direct match, maybe super-class match? for (Class curr = cls; (curr != null); curr = curr.getSuperclass()) { key.reset(curr); ser = _classMappings.get(key); if (ser != null) { return ser; } } } } // No direct match? How about super-interfaces? if (_interfaceMappings != null) { ser = _findInterfaceMapping(cls, key); if (ser != null) { return ser; } // still no matches? Maybe interfaces of super classes if (!cls.isInterface()) { while ((cls = cls.getSuperclass()) != null) { ser = _findInterfaceMapping(cls, key); if (ser != null) { return ser; } } } } return null; } @Override public JsonSerializer findArraySerializer(SerializationConfig config, ArrayType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return findSerializer(config, type, beanDesc, property); } @Override public JsonSerializer findCollectionSerializer(SerializationConfig config, CollectionType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return findSerializer(config, type, beanDesc, property); } @Override public JsonSerializer findCollectionLikeSerializer(SerializationConfig config, CollectionLikeType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return findSerializer(config, type, beanDesc, property); } @Override public JsonSerializer findMapSerializer(SerializationConfig config, MapType type, BeanDescription beanDesc, BeanProperty property, JsonSerializer keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return findSerializer(config, type, beanDesc, property); } @Override public JsonSerializer findMapLikeSerializer(SerializationConfig config, MapLikeType type, BeanDescription beanDesc, BeanProperty property, JsonSerializer keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return findSerializer(config, type, beanDesc, property); } /* /********************************************************** /* Internal methods /********************************************************** */ protected JsonSerializer _findInterfaceMapping(Class cls, ClassKey key) { for (Class iface : cls.getInterfaces()) { key.reset(iface); JsonSerializer ser = _interfaceMappings.get(key); if (ser != null) { return ser; } ser = _findInterfaceMapping(iface, key); if (ser != null) { return ser; } } return null; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/module/SimpleModule.java0000644000175000017500000001703511655120726030737 0ustar jamespagejamespagepackage org.codehaus.jackson.map.module; import java.util.HashMap; import java.util.Map; import org.codehaus.jackson.Version; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.deser.ValueInstantiator; /** * Simple {@link Module} implementation that allows registration * of serializers and deserializers, and bean serializer * and deserializer modifiers. * * @since 1.7 */ public class SimpleModule extends Module { protected final String _name; protected final Version _version; protected SimpleSerializers _serializers = null; protected SimpleDeserializers _deserializers = null; protected SimpleSerializers _keySerializers = null; protected SimpleKeyDeserializers _keyDeserializers = null; /** * Lazily-constructed resolver used for storing mappings from * abstract classes to more specific implementing classes * (which may be abstract or concrete) */ protected SimpleAbstractTypeResolver _abstractTypes = null; /** * Lazily-constructed resolver used for storing mappings from * abstract classes to more specific implementing classes * (which may be abstract or concrete) */ protected SimpleValueInstantiators _valueInstantiators = null; /** * Lazily-constructed map that contains mix-in definitions, indexed * by target class, value being mix-in to apply. * * @since 1.9 */ protected HashMap, Class> _mixins = null; /* /********************************************************** /* Life-cycle: creation /********************************************************** */ public SimpleModule(String name, Version version) { _name = name; _version = version; } /* /********************************************************** /* Simple setters to allow overriding /********************************************************** */ /** * Resets all currently configured serializers. * * @since 1.9 */ public void setSerializers(SimpleSerializers s) { _serializers = s; } /** * Resets all currently configured deserializers. * * @since 1.9 */ public void setDeserializers(SimpleDeserializers d) { _deserializers = d; } /** * Resets all currently configured key serializers. * * @since 1.9 */ public void setKeySerializers(SimpleSerializers ks) { _keySerializers = ks; } /** * Resets all currently configured key deserializers. * * @since 1.9 */ public void setKeyDeserializers(SimpleKeyDeserializers kd) { _keyDeserializers = kd; } /** * Resets currently configured abstract type mappings * * @since 1.9 */ public void setAbstractTypes(SimpleAbstractTypeResolver atr) { _abstractTypes = atr; } /** * Resets all currently configured value instantiators * * @since 1.9 */ public void setValueInstantiators(SimpleValueInstantiators svi) { _valueInstantiators = svi; } /* /********************************************************** /* Configuration methods /********************************************************** */ public SimpleModule addSerializer(JsonSerializer ser) { if (_serializers == null) { _serializers = new SimpleSerializers(); } _serializers.addSerializer(ser); return this; } public SimpleModule addSerializer(Class type, JsonSerializer ser) { if (_serializers == null) { _serializers = new SimpleSerializers(); } _serializers.addSerializer(type, ser); return this; } public SimpleModule addKeySerializer(Class type, JsonSerializer ser) { if (_keySerializers == null) { _keySerializers = new SimpleSerializers(); } _keySerializers.addSerializer(type, ser); return this; } public SimpleModule addDeserializer(Class type, JsonDeserializer deser) { if (_deserializers == null) { _deserializers = new SimpleDeserializers(); } _deserializers.addDeserializer(type, deser); return this; } public SimpleModule addKeyDeserializer(Class type, KeyDeserializer deser) { if (_keyDeserializers == null) { _keyDeserializers = new SimpleKeyDeserializers(); } _keyDeserializers.addDeserializer(type, deser); return this; } /** * Lazily-constructed resolver used for storing mappings from * abstract classes to more specific implementing classes * (which may be abstract or concrete) */ public SimpleModule addAbstractTypeMapping(Class superType, Class subType) { if (_abstractTypes == null) { _abstractTypes = new SimpleAbstractTypeResolver(); } // note: addMapping() will verify arguments _abstractTypes = _abstractTypes.addMapping(superType, subType); return this; } /** * Method for registering {@link ValueInstantiator} to use when deserializing * instances of type beanType. *

* Instantiator is * registered when module is registered for ObjectMapper. */ public SimpleModule addValueInstantiator(Class beanType, ValueInstantiator inst) { if (_valueInstantiators == null) { _valueInstantiators = new SimpleValueInstantiators(); } _valueInstantiators = _valueInstantiators.addValueInstantiator(beanType, inst); return this; } /** * Method for specifying that annotations define by mixinClass * should be "mixed in" with annotations that targetType * has (as if they were directly included on it!). *

* Mix-in annotations are * registered when module is registered for ObjectMapper. */ public SimpleModule setMixInAnnotation(Class targetType, Class mixinClass) { if (_mixins == null) { _mixins = new HashMap, Class>(); } _mixins.put(targetType, mixinClass); return this; } /* /********************************************************** /* Module impl /********************************************************** */ @Override public String getModuleName() { return _name; } @Override public void setupModule(SetupContext context) { if (_serializers != null) { context.addSerializers(_serializers); } if (_deserializers != null) { context.addDeserializers(_deserializers); } if (_keySerializers != null) { context.addKeySerializers(_keySerializers); } if (_keyDeserializers != null) { context.addKeyDeserializers(_keyDeserializers); } if (_abstractTypes != null) { context.addAbstractTypeResolver(_abstractTypes); } if (_valueInstantiators != null) { context.addValueInstantiators(_valueInstantiators); } if (_mixins != null) { for (Map.Entry,Class> entry : _mixins.entrySet()) { context.setMixInAnnotations(entry.getKey(), entry.getValue()); } } } @Override public Version version() { return _version; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/TypeDeserializer.java0000644000175000017500000001036711655120726030340 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.jsontype.TypeIdResolver; /** * Interface for deserializing type information from JSON content, to * type-safely deserialize data into correct polymorphic instance * (when type inclusion has been enabled for type handled). *

* Separate deserialization methods are needed because serialized * form for inclusion mechanism {@link As#PROPERTY} * is slighty different if value is not expressed as JSON Object: * and as such both type deserializer and serializer need to * JSON Object form (array, object or other (== scalar)) being * used. * * @since 1.5 * @author tatus */ public abstract class TypeDeserializer { /* /********************************************************** /* Introspection /********************************************************** */ /** * Accessor for type information inclusion method * that deserializer uses; indicates how type information * is (expected to be) embedded in JSON input. */ public abstract As getTypeInclusion(); /** * Name of property that contains type information, if * property-based inclusion is used. */ public abstract String getPropertyName(); /** * Accessor for object that handles conversions between * types and matching type ids. */ public abstract TypeIdResolver getTypeIdResolver(); /** * Accessor for "default implementation" type; optionally defined * class to use in cases where type id is not * accessible for some reason (either missing, or can not be * resolved) * * @since 1.9 */ public abstract Class getDefaultImpl(); /* /********************************************************* /* Type deserialization methods /********************************************************** */ /** * Method called to let this type deserializer handle * deserialization of "typed" object, when value itself * is serialized as JSON Object (regardless of Java type). * Method needs to figure out intended * polymorphic type, locate {@link JsonDeserializer} to use, and * call it with JSON data to deserializer (which does not contain * type information). */ public abstract Object deserializeTypedFromObject(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException; /** * Method called to let this type deserializer handle * deserialization of "typed" object, when value itself * is serialized as JSON Array (regardless of Java type). * Method needs to figure out intended * polymorphic type, locate {@link JsonDeserializer} to use, and * call it with JSON data to deserializer (which does not contain * type information). */ public abstract Object deserializeTypedFromArray(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException; /** * Method called to let this type deserializer handle * deserialization of "typed" object, when value itself * is serialized as a scalar JSON value (something other * than Array or Object), regardless of Java type. * Method needs to figure out intended * polymorphic type, locate {@link JsonDeserializer} to use, and * call it with JSON data to deserializer (which does not contain * type information). */ public abstract Object deserializeTypedFromScalar(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException; /** * Method called to let this type deserializer handle * deserialization of "typed" object, when value itself * may have been serialized using any kind of JSON value * (Array, Object, scalar). Should only be called if JSON * serialization is polymorphic (not Java type); for example when * using JSON node representation, or "untyped" Java object * (which may be Map, Collection, wrapper/primitive etc). */ public abstract Object deserializeTypedFromAny(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/DeserializerProvider.java0000644000175000017500000001562111655120726031207 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.io.SerializedString; import org.codehaus.jackson.map.deser.BeanDeserializerModifier; import org.codehaus.jackson.map.deser.ValueInstantiators; import org.codehaus.jackson.type.JavaType; /** * Abstract class that defines API used by {@link ObjectMapper} and * {@link JsonDeserializer}s to obtain deserializers capable of * re-constructing instances of handled type from JSON content. */ public abstract class DeserializerProvider { protected DeserializerProvider() { } /* /********************************************************** /* Fluent factory methods /********************************************************** */ /** * Method that sub-classes need to override, to ensure that fluent-factory * methods will produce proper sub-type. * * @since 1.9 */ public abstract DeserializerProvider withFactory(DeserializerFactory factory); /** * Method that is to configure {@link DeserializerFactory} that provider has * to use specified deserializer provider, with highest precedence (that is, * additional providers have higher precedence than default one or previously * added ones) * * @since 1.7 */ public abstract DeserializerProvider withAdditionalDeserializers(Deserializers d); /** * @since 1.8 */ public abstract DeserializerProvider withAdditionalKeyDeserializers(KeyDeserializers d); /** * @since 1.7 */ public abstract DeserializerProvider withDeserializerModifier(BeanDeserializerModifier modifier); /** * @since 1.8 */ public abstract DeserializerProvider withAbstractTypeResolver(AbstractTypeResolver resolver); /** * Method that will construct a new instance with specified additional value instantiators * (i.e. does NOT replace existing ones) * * @since 1.9 */ public abstract DeserializerProvider withValueInstantiators(ValueInstantiators instantiators); /* /********************************************************** /* General deserializer locating method /********************************************************** */ /** * Method called to get hold of a deserializer for a value of given type; * or if no such deserializer can be found, a default handler (which * may do a best-effort generic serialization or just simply * throw an exception when invoked). *

* Note: this method is only called for value types; not for keys. * Key deserializers can be accessed using {@link #findKeyDeserializer}. * * @param config Deserialization configuration * @param propertyType Declared type of the value to deserializer (obtained using * 'setter' method signature and/or type annotations * @param property Object that represents accessor for property value; field, * setter method or constructor parameter. * * @throws JsonMappingException if there are fatal problems with * accessing suitable deserializer; including that of not * finding any serializer */ public abstract JsonDeserializer findValueDeserializer(DeserializationConfig config, JavaType propertyType, BeanProperty property) throws JsonMappingException; /** * Method called to locate deserializer for given type, as well as matching * type deserializer (if one is needed); and if type deserializer is needed, * construct a "wrapped" deserializer that can extract and use type information * for calling actual deserializer. *

* Since this method is only called for root elements, no referral information * is taken. * * @since 1.5 */ public abstract JsonDeserializer findTypedValueDeserializer(DeserializationConfig config, JavaType type, BeanProperty property) throws JsonMappingException; /** * Method called to get hold of a deserializer to use for deserializing * keys for {@link java.util.Map}. * * @throws JsonMappingException if there are fatal problems with * accessing suitable key deserializer; including that of not * finding any serializer */ public abstract KeyDeserializer findKeyDeserializer(DeserializationConfig config, JavaType keyType, BeanProperty property) throws JsonMappingException; /** * Method called to find out whether provider would be able to find * a deserializer for given type, using a root reference (i.e. not * through fields or membership in an array or collection) */ public abstract boolean hasValueDeserializerFor(DeserializationConfig config, JavaType type); /* /********************************************************** /* Additional type handling methods, related /********************************************************** */ /** * Method that can be called to try to resolve an abstract type * (interface, abstract class) into a concrete type, or at least * something "more concrete" (abstract class instead of interface). * Will either return passed type, or a more specific type. * * @since 1.9 */ public abstract JavaType mapAbstractType(DeserializationConfig config, JavaType type) throws JsonMappingException; /** * Method that can be used to try find expected root name for given type * * @since 1.9 */ public abstract SerializedString findExpectedRootName(DeserializationConfig config, JavaType type) throws JsonMappingException; /* /********************************************************** /* Access to caching aspects /********************************************************** */ /** * Method that can be used to determine how many deserializers this * provider is caching currently * (if it does caching: default implementation does) * Exact count depends on what kind of deserializers get cached; * default implementation caches only dynamically constructed deserializers, * but not eagerly constructed standard deserializers (which is different * from how serializer provider works). *

* The main use case for this method is to allow conditional flushing of * deserializer cache, if certain number of entries is reached. * * @since 1.4 */ public abstract int cachedDeserializersCount(); /** * Method that will drop all dynamically constructed deserializers (ones that * are counted as result value for {@link #cachedDeserializersCount}). * This can be used to remove memory usage (in case some deserializers are * only used once or so), or to force re-construction of deserializers after * configuration changes for mapper than owns the provider. * * @since 1.4 */ public abstract void flushCachedDeserializers(); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/DeserializationContext.java0000644000175000017500000002050511655120726031542 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import java.util.*; import org.codehaus.jackson.*; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.map.util.ArrayBuilders; import org.codehaus.jackson.map.util.ObjectBuffer; import org.codehaus.jackson.node.JsonNodeFactory; import org.codehaus.jackson.type.JavaType; /** * Context for deserialization process. Used to allow passing in configuration * settings and reusable temporary objects (scrap arrays, containers). */ public abstract class DeserializationContext { protected final DeserializationConfig _config; /** * @since 1.7 */ protected final int _featureFlags; /* /********************************************************** /* Life-cycle /********************************************************** */ protected DeserializationContext(DeserializationConfig config) { _config = config; _featureFlags = config._featureFlags; } /* /********************************************************** /* Configuration methods /********************************************************** */ /** * Method for accessing configuration setting object for * currently active deserialization. */ public DeserializationConfig getConfig() { return _config; } /** * Returns provider that can be used for dynamically locating * other deserializers during runtime. * * @since 1.5 */ public DeserializerProvider getDeserializerProvider() { // will be overridden by impl class return null; } /** * Convenience method for checking whether specified on/off * feature is enabled */ public boolean isEnabled(DeserializationConfig.Feature feat) { /* 03-Dec-2010, tatu: minor shortcut; since this is called quite often, * let's use a local copy of feature settings: */ return (_featureFlags & feat.getMask()) != 0; } /** * Convenience method for accessing the default Base64 encoding * used for decoding base64 encoded binary content. * Same as calling: *

     *  getConfig().getBase64Variant();
     *
*/ public Base64Variant getBase64Variant() { return _config.getBase64Variant(); } /** * Accessor for getting access to the underlying JSON parser used * for deserialization. */ public abstract JsonParser getParser(); public final JsonNodeFactory getNodeFactory() { return _config.getNodeFactory(); } /** * @since 1.8 */ public JavaType constructType(Class cls) { return _config.constructType(cls); } /** * @since 1.9 */ public TypeFactory getTypeFactory() { return _config.getTypeFactory(); } /** * @since 1.9 */ public abstract Object findInjectableValue(Object valueId, BeanProperty forProperty, Object beanInstance); /* /********************************************************** /* Methods for accessing reusable/recyclable helper objects /********************************************************** */ /** * Method that can be used to get access to a reusable ObjectBuffer, * useful for efficiently constructing Object arrays and Lists. * Note that leased buffers should be returned once deserializer * is done, to allow for reuse during same round of deserialization. */ public abstract ObjectBuffer leaseObjectBuffer(); /** * Method to call to return object buffer previously leased with * {@link #leaseObjectBuffer}. * * @param buf Returned object buffer */ public abstract void returnObjectBuffer(ObjectBuffer buf); /** * Method for accessing object useful for building arrays of * primitive types (such as int[]). */ public abstract ArrayBuilders getArrayBuilders(); /* /********************************************************** /* Parsing methods that may use reusable/-cyclable objects /********************************************************** */ /** * Convenience method for parsing a Date from given String, using * currently configured date format (accessed using * {@link DeserializationConfig#getDateFormat()}). *

* Implementation will handle thread-safety issues related to * date formats such that first time this method is called, * date format is cloned, and cloned instance will be retained * for use during this deserialization round. */ public abstract java.util.Date parseDate(String dateStr) throws IllegalArgumentException; /** * Convenience method for constructing Calendar instance set * to specified time, to be modified and used by caller. */ public abstract Calendar constructCalendar(Date d); /* /********************************************************** /* Methods for problem handling, reporting /********************************************************** */ /** * Method deserializers can call to inform configured {@link DeserializationProblemHandler}s * of an unrecognized property. * * @return True if there was a configured problem handler that was able to handle the * proble * * @since 1.5 */ public abstract boolean handleUnknownProperty(JsonParser jp, JsonDeserializer deser, Object instanceOrClass, String propName) throws IOException, JsonProcessingException; /** * Helper method for constructing generic mapping exception for specified type */ public abstract JsonMappingException mappingException(Class targetClass); /** * @since 1.9 */ public abstract JsonMappingException mappingException(Class targetClass, JsonToken t); /** * Helper method for constructing generic mapping exception with specified * message and current location information * * @since 1.7 */ public JsonMappingException mappingException(String message) { return JsonMappingException.from(getParser(), message); } /** * Helper method for constructing instantiation exception for specified type, * to indicate problem with physically constructing instance of * specified class (missing constructor, exception from constructor) */ public abstract JsonMappingException instantiationException(Class instClass, Throwable t); public abstract JsonMappingException instantiationException(Class instClass, String msg); /** * Helper method for constructing exception to indicate that input JSON * String was not in recognized format for deserializing into given type. */ public abstract JsonMappingException weirdStringException(Class instClass, String msg); /** * Helper method for constructing exception to indicate that input JSON * Number was not suitable for deserializing into given type. */ public abstract JsonMappingException weirdNumberException(Class instClass, String msg); /** * Helper method for constructing exception to indicate that given JSON * Object field name was not in format to be able to deserialize specified * key type. */ public abstract JsonMappingException weirdKeyException(Class keyClass, String keyValue, String msg); /** * Helper method for indicating that the current token was expected to be another * token. */ public abstract JsonMappingException wrongTokenException(JsonParser jp, JsonToken expToken, String msg); /** * Helper method for constructing exception to indicate that JSON Object * field name did not map to a known property of type being * deserialized. * * @param instanceOrClass Either value being populated (if one has been * instantiated), or Class that indicates type that would be (or * have been) instantiated */ public abstract JsonMappingException unknownFieldException(Object instanceOrClass, String fieldName); /** * Helper method for constructing exception to indicate that given * type id (parsed from JSON) could not be converted to a Java type. * * @since 1.5 */ public abstract JsonMappingException unknownTypeException(JavaType baseType, String id); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/DeserializationConfig.java0000644000175000017500000010423311655120726031324 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.text.DateFormat; import java.util.*; import org.codehaus.jackson.Base64Variant; import org.codehaus.jackson.Base64Variants; import org.codehaus.jackson.annotate.*; import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility; import org.codehaus.jackson.map.deser.ValueInstantiator; import org.codehaus.jackson.map.introspect.Annotated; import org.codehaus.jackson.map.introspect.AnnotatedClass; import org.codehaus.jackson.map.introspect.NopAnnotationIntrospector; import org.codehaus.jackson.map.introspect.VisibilityChecker; import org.codehaus.jackson.map.jsontype.SubtypeResolver; import org.codehaus.jackson.map.jsontype.TypeResolverBuilder; import org.codehaus.jackson.map.type.ClassKey; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.map.util.ClassUtil; import org.codehaus.jackson.map.util.LinkedNode; import org.codehaus.jackson.node.JsonNodeFactory; import org.codehaus.jackson.type.JavaType; /** * Object that contains baseline configuration for deserialization * process. An instance is owned by {@link ObjectMapper}, which makes * a copy that is passed during serialization process to * {@link DeserializerProvider} and {@link DeserializerFactory}. *

* Note: although configuration settings can be changed at any time * (for factories and instances), they are not guaranteed to have * effect if called after constructing relevant mapper or deserializer * instance. This because some objects may be configured, constructed and * cached first time they are needed. *

* As of version 1.9, the goal is to make this class eventually immutable. * Because of this, existing methods that allow changing state of this * instance are deprecated in favor of methods that create new instances * with different configuration ("fluent factories") */ public class DeserializationConfig extends MapperConfig.Impl { /** * Enumeration that defines togglable features that guide * the serialization feature. */ public enum Feature implements MapperConfig.ConfigFeature { /* /****************************************************** * Introspection features /****************************************************** */ /** * Feature that determines whether annotation introspection * is used for configuration; if enabled, configured * {@link AnnotationIntrospector} will be used: if disabled, * no annotations are considered. *

* Feature is enabled by default. * * @since 1.2 */ USE_ANNOTATIONS(true), /** * Feature that determines whether "setter" methods are * automatically detected based on standard Bean naming convention * or not. If yes, then all public one-argument methods that * start with prefix "set" * are considered setters. If disabled, only methods explicitly * annotated are considered setters. *

* Note that this feature has lower precedence than per-class * annotations, and is only used if there isn't more granular * configuration available. *

* Feature is enabled by default. */ AUTO_DETECT_SETTERS(true), /** * Feature that determines whether "creator" methods are * automatically detected by consider public constructors, * and static single argument methods with name "valueOf". * If disabled, only methods explicitly annotated are considered * creator methods (except for the no-arg default constructor which * is always considered a factory method). *

* Note that this feature has lower precedence than per-class * annotations, and is only used if there isn't more granular * configuration available. *

* Feature is enabled by default. */ AUTO_DETECT_CREATORS(true), /** * Feature that determines whether non-static fields are recognized as * properties. * If yes, then all public member fields * are considered as properties. If disabled, only fields explicitly * annotated are considered property fields. *

* Note that this feature has lower precedence than per-class * annotations, and is only used if there isn't more granular * configuration available. *

* Feature is enabled by default. * * @since 1.1 */ AUTO_DETECT_FIELDS(true), /** * Feature that determines whether otherwise regular "getter" * methods (but only ones that handle Collections and Maps, * not getters of other type) * can be used for purpose of getting a reference to a Collection * and Map to modify the property, without requiring a setter * method. * This is similar to how JAXB framework sets Collections and * Maps: no setter is involved, just setter. *

* Note that such getters-as-setters methods have lower * precedence than setters, so they are only used if no * setter is found for the Map/Collection property. *

* Feature is enabled by default. */ USE_GETTERS_AS_SETTERS(true), /** * Feature that determines whether method and field access * modifier settings can be overridden when accessing * properties. If enabled, method * {@link java.lang.reflect.AccessibleObject#setAccessible} * may be called to enable access to otherwise unaccessible * objects. */ CAN_OVERRIDE_ACCESS_MODIFIERS(true), /* /****************************************************** /* Type conversion features /****************************************************** */ /** * Feature that determines whether Json floating point numbers * are to be deserialized into {@link java.math.BigDecimal}s * if only generic type description (either {@link Object} or * {@link Number}, or within untyped {@link java.util.Map} * or {@link java.util.Collection} context) is available. * If enabled such values will be deserialized as {@link java.math.BigDecimal}s; * if disabled, will be deserialized as {@link Double}s. *

* Feature is disabled by default, meaning that "untyped" floating * point numbers will by default be deserialized as {@link Double}s * (choice is for performance reason -- BigDecimals are slower than * Doubles) */ USE_BIG_DECIMAL_FOR_FLOATS(false), /** * Feature that determines whether Json integral (non-floating-point) * numbers are to be deserialized into {@link java.math.BigInteger}s * if only generic type description (either {@link Object} or * {@link Number}, or within untyped {@link java.util.Map} * or {@link java.util.Collection} context) is available. * If enabled such values will be deserialized as * {@link java.math.BigInteger}s; * if disabled, will be deserialized as "smallest" available type, * which is either {@link Integer}, {@link Long} or * {@link java.math.BigInteger}, depending on number of digits. *

* Feature is disabled by default, meaning that "untyped" floating * point numbers will by default be deserialized using whatever * is the most compact integral type, to optimize efficiency. */ USE_BIG_INTEGER_FOR_INTS(false), // [JACKSON-652] /** * Feature that determines whether JSON Array is mapped to * Object[] or List<Object> when binding * "untyped" objects (ones with nominal type of java.lang.Object). * If true, binds as Object[]; if false, as List<Object>. *

* Feature is disabled by default, meaning that JSON arrays are bound as * {@link java.util.List}s. * * @since 1.9 */ USE_JAVA_ARRAY_FOR_JSON_ARRAY(false), /** * Feature that determines standard deserialization mechanism used for * Enum values: if enabled, Enums are assumed to have been serialized using * return value of Enum.toString(); * if disabled, return value of Enum.name() is assumed to have been used. * Since pre-1.6 method was to use Enum name, this is the default. *

* Note: this feature should usually have same value * as {@link SerializationConfig.Feature#WRITE_ENUMS_USING_TO_STRING}. *

* For further details, check out [JACKSON-212] * * @since 1.6 */ READ_ENUMS_USING_TO_STRING(false), /* /****************************************************** * Error handling features /****************************************************** */ /** * Feature that determines whether encountering of unknown * properties (ones that do not map to a property, and there is * no "any setter" or handler that can handle it) * should result in a failure (by throwing a * {@link JsonMappingException}) or not. * This setting only takes effect after all other handling * methods for unknown properties have been tried, and * property remains unhandled. *

* Feature is enabled by default, meaning that * {@link JsonMappingException} is thrown if an unknown property * is encountered. This is the implicit default prior to * introduction of the feature. * * @since 1.2 */ FAIL_ON_UNKNOWN_PROPERTIES(true), /** * Feature that determines whether encountering of JSON null * is an error when deserializing into Java primitive types * (like 'int' or 'double'). If it is, a JsonProcessingException * is thrown to indicate this; if not, default value is used * (0 for 'int', 0.0 for double, same defaulting as what JVM uses). *

* Feature is disabled by default (to be consistent with behavior * of Jackson 1.6), * i.e. to allow use of nulls for primitive properties. * * @since 1.7 */ FAIL_ON_NULL_FOR_PRIMITIVES(false), /** * Feature that determines whether JSON integer numbers are valid * values to be used for deserializing Java enum values. * If set to 'false' numbers are acceptable and are used to map to * ordinal() of matching enumeration value; if 'true', numbers are * not allowed and a {@link JsonMappingException} will be thrown. * Latter behavior makes sense if there is concern that accidental * mapping from integer values to enums might happen (and when enums * are always serialized as JSON Strings) *

* Feature is disabled by default (to be consistent with behavior * of Jackson 1.6), * i.e. to allow use of JSON integers for Java enums. * * @since 1.7 */ FAIL_ON_NUMBERS_FOR_ENUMS(false), /** * Feature that determines whether Jackson code should catch * and wrap {@link Exception}s (but never {@link Error}s!) * to add additional information about * location (within input) of problem or not. If enabled, * most exceptions will be caught and re-thrown (exception * specifically being that {@link java.io.IOException}s may be passed * as is, since they are declared as throwable); this can be * convenient both in that all exceptions will be checked and * declared, and so there is more contextual information. * However, sometimes calling application may just want "raw" * unchecked exceptions passed as is. *

* Feature is enabled by default, and is similar in behavior * to default prior to 1.7. * * @since 1.7 */ WRAP_EXCEPTIONS(true), /* /****************************************************** * Structural conversion features /****************************************************** */ /** * Feature that determines whether it is acceptable to coerce non-array * (in JSON) values to work with Java collection (arrays, java.util.Collection) * types. If enabled, collection deserializers will try to handle non-array * values as if they had "implicit" surrounding JSON array. * This feature is meant to be used for compatibility/interoperability reasons, * to work with packages (such as XML-to-JSON converters) that leave out JSON * array in cases where there is just a single element in array. * * @since 1.8 */ ACCEPT_SINGLE_VALUE_AS_ARRAY(false), /** * Feature to allow "unwrapping" root-level JSON value, to match setting of * {@link SerializationConfig.Feature#WRAP_ROOT_VALUE} used for serialization. * Will verify that the root JSON value is a JSON Object, and that it has * a single property with expected root name. If not, a * {@link JsonMappingException} is thrown; otherwise value of the wrapped property * will be deserialized as if it was the root value. * * @since 1.9 */ UNWRAP_ROOT_VALUE(false), /* /****************************************************** * Value conversion features /****************************************************** */ /** * Feature that can be enabled to allow JSON empty String * value ("") to be bound to POJOs as null. * If disabled, standard POJOs can only be bound from JSON null or * JSON Object (standard meaning that no custom deserializers or * constructors are defined; both of which can add support for other * kinds of JSON values); if enable, empty JSON String can be taken * to be equivalent of JSON null. * * @since 1.8 */ ACCEPT_EMPTY_STRING_AS_NULL_OBJECT(false) ; final boolean _defaultState; private Feature(boolean defaultState) { _defaultState = defaultState; } @Override public boolean enabledByDefault() { return _defaultState; } @Override public int getMask() { return (1 << ordinal()); } } /* /********************************************************** /* Configuration settings for deserialization /********************************************************** */ /** * Linked list that contains all registered problem handlers. * Implementation as front-added linked list allows for sharing * of the list (tail) without copying the list. */ protected LinkedNode _problemHandlers; /** * Factory used for constructing {@link org.codehaus.jackson.JsonNode} instances. * * @since 1.6 */ protected final JsonNodeFactory _nodeFactory; /** * Feature flag from {@link SerializationConfig} which is needed to * know if serializer will by default sort properties in * alphabetic order. *

* Note that although this property is not marked as final, * it is handled like it was, except for the fact that it is * assigned with a call to {@link #passSerializationFeatures} * instead of constructor. * * @since 1.9 */ protected boolean _sortPropertiesAlphabetically; /* /********************************************************** /* Life-cycle, constructors /********************************************************** */ /** * Constructor used by ObjectMapper to create default configuration object instance. */ public DeserializationConfig(ClassIntrospector intr, AnnotationIntrospector annIntr, VisibilityChecker vc, SubtypeResolver subtypeResolver, PropertyNamingStrategy propertyNamingStrategy, TypeFactory typeFactory, HandlerInstantiator handlerInstantiator) { super(intr, annIntr, vc, subtypeResolver, propertyNamingStrategy, typeFactory, handlerInstantiator, collectFeatureDefaults(DeserializationConfig.Feature.class)); _nodeFactory = JsonNodeFactory.instance; } /** * @since 1.8 */ protected DeserializationConfig(DeserializationConfig src) { this(src, src._base); } /** * Copy constructor used to create a non-shared instance with given mix-in * annotation definitions and subtype resolver. * * @since 1.8 */ private DeserializationConfig(DeserializationConfig src, HashMap> mixins, SubtypeResolver str) { this(src, src._base); _mixInAnnotations = mixins; _subtypeResolver = str; } /** * @since 1.8 */ protected DeserializationConfig(DeserializationConfig src, MapperConfig.Base base) { super(src, base, src._subtypeResolver); _problemHandlers = src._problemHandlers; _nodeFactory = src._nodeFactory; _sortPropertiesAlphabetically = src._sortPropertiesAlphabetically; } /** * @since 1.8 */ protected DeserializationConfig(DeserializationConfig src, JsonNodeFactory f) { super(src); _problemHandlers = src._problemHandlers; _nodeFactory = f; _sortPropertiesAlphabetically = src._sortPropertiesAlphabetically; } /** * @since 1.9 */ protected DeserializationConfig(DeserializationConfig src, int featureFlags) { super(src, featureFlags); _problemHandlers = src._problemHandlers; _nodeFactory = src._nodeFactory; _sortPropertiesAlphabetically = src._sortPropertiesAlphabetically; } /** * Helper method to be called right after creating a non-shared * instance, needed to pass state of feature(s) shared with * SerializationConfig. * * Since 1.9 */ protected DeserializationConfig passSerializationFeatures(int serializationFeatureFlags) { _sortPropertiesAlphabetically = (serializationFeatureFlags & SerializationConfig.Feature.SORT_PROPERTIES_ALPHABETICALLY.getMask()) != 0; return this; } /* /********************************************************** /* Life-cycle, factory methods from MapperConfig /********************************************************** */ @Override public DeserializationConfig withClassIntrospector(ClassIntrospector ci) { return new DeserializationConfig(this, _base.withClassIntrospector(ci)); } @Override public DeserializationConfig withAnnotationIntrospector(AnnotationIntrospector ai) { return new DeserializationConfig(this, _base.withAnnotationIntrospector(ai)); } @Override public DeserializationConfig withVisibilityChecker(VisibilityChecker vc) { return new DeserializationConfig(this, _base.withVisibilityChecker(vc)); } @Override public DeserializationConfig withVisibility(JsonMethod forMethod, JsonAutoDetect.Visibility visibility) { return new DeserializationConfig(this, _base.withVisibility(forMethod, visibility)); } @Override public DeserializationConfig withTypeResolverBuilder(TypeResolverBuilder trb) { return new DeserializationConfig(this, _base.withTypeResolverBuilder(trb)); } @Override public DeserializationConfig withSubtypeResolver(SubtypeResolver str) { DeserializationConfig cfg = new DeserializationConfig(this); cfg._subtypeResolver = str; return cfg; } @Override public DeserializationConfig withPropertyNamingStrategy(PropertyNamingStrategy pns) { return new DeserializationConfig(this, _base.withPropertyNamingStrategy(pns)); } @Override public DeserializationConfig withTypeFactory(TypeFactory tf) { return (tf == _base.getTypeFactory()) ? this : new DeserializationConfig(this, _base.withTypeFactory(tf)); } @Override public DeserializationConfig withDateFormat(DateFormat df) { return (df == _base.getDateFormat()) ? this : new DeserializationConfig(this, _base.withDateFormat(df)); } @Override public DeserializationConfig withHandlerInstantiator(HandlerInstantiator hi) { return (hi == _base.getHandlerInstantiator()) ? this : new DeserializationConfig(this, _base.withHandlerInstantiator(hi)); } @Override public DeserializationConfig withInsertedAnnotationIntrospector(AnnotationIntrospector ai) { return new DeserializationConfig(this, _base.withInsertedAnnotationIntrospector(ai)); } @Override public DeserializationConfig withAppendedAnnotationIntrospector(AnnotationIntrospector ai) { return new DeserializationConfig(this, _base.withAppendedAnnotationIntrospector(ai)); } /* /********************************************************** /* Life-cycle, deserialization-specific factory methods /********************************************************** */ /** * Fluent factory method that will construct a new instance with * specified {@link JsonNodeFactory} * * @since 1.8 */ public DeserializationConfig withNodeFactory(JsonNodeFactory f) { return new DeserializationConfig(this, f); } /** * Fluent factory method that will construct and return a new configuration * object instance with specified features enabled. * * @since 1.9 */ @Override public DeserializationConfig with(DeserializationConfig.Feature... features) { int flags = _featureFlags; for (Feature f : features) { flags |= f.getMask(); } return new DeserializationConfig(this, flags); } /** * Fluent factory method that will construct and return a new configuration * object instance with specified features disabled. * * @since 1.9 */ @Override public DeserializationConfig without(DeserializationConfig.Feature... features) { int flags = _featureFlags; for (Feature f : features) { flags &= ~f.getMask(); } return new DeserializationConfig(this, flags); } /* /********************************************************** /* MapperConfig implementation /********************************************************** */ /** * Method that checks class annotations that the argument Object has, * and modifies settings of this configuration object accordingly, * similar to how those annotations would affect actual value classes * annotated with them, but with global scope. Note that not all * annotations have global significance, and thus only subset of * Jackson annotations will have any effect. *

* Ones that are known to have effect are: *

    *
  • {@link JsonAutoDetect}
  • *
* * @param cls Class of which class annotations to use * for changing configuration settings * * @deprecated Since 1.9, it is preferably to explicitly configure * instances; this method also modifies existing instance which is * against immutable design goals of this class. */ @Deprecated @Override public void fromAnnotations(Class cls) { /* no class annotation for: * * - CAN_OVERRIDE_ACCESS_MODIFIERS * - USE_BIG_DECIMAL_FOR_FLOATS * - USE_BIG_INTEGER_FOR_INTS * - USE_GETTERS_AS_SETTERS */ /* 10-Jul-2009, tatu: Should be able to just pass null as * 'MixInResolver'; no mix-ins set at this point */ AnnotationIntrospector ai = getAnnotationIntrospector(); AnnotatedClass ac = AnnotatedClass.construct(cls, ai, null); // visibility checks handled via separate checker object... VisibilityChecker prevVc = getDefaultVisibilityChecker(); _base = _base.withVisibilityChecker(ai.findAutoDetectVisibility(ac, prevVc)); } /** * Method that is called to create a non-shared copy of the configuration * to be used for a deserialization operation. * Note that if sub-classing * and sub-class has additional instance methods, * this method must be overridden to produce proper sub-class * instance. */ @Override public DeserializationConfig createUnshared(SubtypeResolver subtypeResolver) { HashMap> mixins = _mixInAnnotations; // ensure that we assume sharing at this point: _mixInAnnotationsShared = true; return new DeserializationConfig(this, mixins, subtypeResolver); } /** * Method for getting {@link AnnotationIntrospector} configured * to introspect annotation values used for configuration. */ @Override public AnnotationIntrospector getAnnotationIntrospector() { /* 29-Jul-2009, tatu: it's now possible to disable use of * annotations; can be done using "no-op" introspector */ if (isEnabled(Feature.USE_ANNOTATIONS)) { return super.getAnnotationIntrospector(); } return NopAnnotationIntrospector.instance; } /** * Accessor for getting bean description that only contains class * annotations: useful if no getter/setter/creator information is needed. *

* Note: part of {@link MapperConfig} since 1.7 */ @SuppressWarnings("unchecked") @Override public T introspectClassAnnotations(JavaType type) { return (T) getClassIntrospector().forClassAnnotations(this, type, this); } /** * Accessor for getting bean description that only contains immediate class * annotations: ones from the class, and its direct mix-in, if any, but * not from super types. *

* Note: part of {@link MapperConfig} since 1.7 */ @Override @SuppressWarnings("unchecked") public T introspectDirectClassAnnotations(JavaType type) { return (T) getClassIntrospector().forDirectClassAnnotations(this, type, this); } @Override public boolean isAnnotationProcessingEnabled() { return isEnabled(Feature.USE_ANNOTATIONS); } @Override public boolean canOverrideAccessModifiers() { return isEnabled(Feature.CAN_OVERRIDE_ACCESS_MODIFIERS); } @Override public boolean shouldSortPropertiesAlphabetically() { return _sortPropertiesAlphabetically; } @Override public VisibilityChecker getDefaultVisibilityChecker() { VisibilityChecker vchecker = super.getDefaultVisibilityChecker(); if (!isEnabled(DeserializationConfig.Feature.AUTO_DETECT_SETTERS)) { vchecker = vchecker.withSetterVisibility(Visibility.NONE); } if (!isEnabled(DeserializationConfig.Feature.AUTO_DETECT_CREATORS)) { vchecker = vchecker.withCreatorVisibility(Visibility.NONE); } if (!isEnabled(DeserializationConfig.Feature.AUTO_DETECT_FIELDS)) { vchecker = vchecker.withFieldVisibility(Visibility.NONE); } return vchecker; } /* /********************************************************** /* MapperConfig overrides for 1.8 backwards compatibility /********************************************************** */ /* NOTE: these are overloads we MUST have, but that were missing * from 1.9.0 and 1.9.1. Type erasure can bite in the ass... *

* NOTE: will remove either these variants, or base class one, in 2.0. */ /** * An overload for {@link MapperConfig#isEnabled(MapperConfig.ConfigFeature)}, * needed for backwards-compatibility. *

* NOTE: will remove either this variant, or base class one, in 2.0./ * * @since 1.0 However, note that version 1.9.0 and 1.9.1 accidentally missed * this overloaded variant */ public boolean isEnabled(DeserializationConfig.Feature f) { return (_featureFlags & f.getMask()) != 0; } /** * @deprecated Since 1.9, it is preferable to use {@link #with} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated @Override public void enable(DeserializationConfig.Feature f) { super.enable(f); } /** * @deprecated Since 1.9, it is preferable to use {@link #without} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated @Override public void disable(DeserializationConfig.Feature f) { super.disable(f); } /** * @deprecated Since 1.9, it is preferable to use {@link #without} and {@link #with} instead; * this method is deprecated as it modifies current instance instead of * creating a new one (as the goal is to make this class immutable) */ @Deprecated @Override public void set(DeserializationConfig.Feature f, boolean state) { super.set(f, state); } /* /********************************************************** /* Problem handlers /********************************************************** */ /** * Method for getting head of the problem handler chain. May be null, * if no handlers have been added. */ public LinkedNode getProblemHandlers() { return _problemHandlers; } /** * Method that can be used to add a handler that can (try to) * resolve non-fatal deserialization problems. */ public void addHandler(DeserializationProblemHandler h) { /* Sanity check: let's prevent adding same handler multiple * times */ if (!LinkedNode.contains(_problemHandlers, h)) { _problemHandlers = new LinkedNode(h, _problemHandlers); } } /** * Method for removing all configured problem handlers; usually done to replace * existing handler(s) with different one(s) * * @since 1.1 */ public void clearHandlers() { _problemHandlers = null; } /* /********************************************************** /* Other configuration /********************************************************** */ /** * Method called during deserialization if Base64 encoded content * needs to be decoded. Default version just returns default Jackson * uses, which is modified-mime which does not add linefeeds (because * those would have to be escaped in JSON strings). */ public Base64Variant getBase64Variant() { return Base64Variants.getDefaultVariant(); } /** * @since 1.6 */ public final JsonNodeFactory getNodeFactory() { return _nodeFactory; } /* /********************************************************** /* Introspection methods /********************************************************** */ /** * Method that will introspect full bean properties for the purpose * of building a bean deserializer * * @param type Type of class to be introspected */ @SuppressWarnings("unchecked") public T introspect(JavaType type) { return (T) getClassIntrospector().forDeserialization(this, type, this); } /** * Method that will introspect subset of bean properties needed to * construct bean instance. */ @SuppressWarnings("unchecked") public T introspectForCreation(JavaType type) { return (T) getClassIntrospector().forCreation(this, type, this); } /* /********************************************************** /* Extended API: handler instantiation /********************************************************** */ @SuppressWarnings("unchecked") public JsonDeserializer deserializerInstance(Annotated annotated, Class> deserClass) { HandlerInstantiator hi = getHandlerInstantiator(); if (hi != null) { JsonDeserializer deser = hi.deserializerInstance(this, annotated, deserClass); if (deser != null) { return (JsonDeserializer) deser; } } return (JsonDeserializer) ClassUtil.createInstance(deserClass, canOverrideAccessModifiers()); } public KeyDeserializer keyDeserializerInstance(Annotated annotated, Class keyDeserClass) { HandlerInstantiator hi = getHandlerInstantiator(); if (hi != null) { KeyDeserializer keyDeser = hi.keyDeserializerInstance(this, annotated, keyDeserClass); if (keyDeser != null) { return (KeyDeserializer) keyDeser; } } return (KeyDeserializer) ClassUtil.createInstance(keyDeserClass, canOverrideAccessModifiers()); } public ValueInstantiator valueInstantiatorInstance(Annotated annotated, Class instClass) { HandlerInstantiator hi = getHandlerInstantiator(); if (hi != null) { ValueInstantiator inst = hi.valueInstantiatorInstance(this, annotated, instClass); if (inst != null) { return (ValueInstantiator) inst; } } return (ValueInstantiator) ClassUtil.createInstance(instClass, canOverrideAccessModifiers()); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/0000755000175000017500000000000011672662540025163 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/RootNameLookup.java0000644000175000017500000000363411655120726030746 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import org.codehaus.jackson.io.SerializedString; import org.codehaus.jackson.map.AnnotationIntrospector; import org.codehaus.jackson.map.MapperConfig; import org.codehaus.jackson.map.introspect.AnnotatedClass; import org.codehaus.jackson.map.introspect.BasicBeanDescription; import org.codehaus.jackson.map.type.ClassKey; import org.codehaus.jackson.type.JavaType; /** * Helper class for caching resolved root names. */ public class RootNameLookup { /** * For efficient operation, let's try to minimize number of times we * need to introspect root element name to use. */ protected LRUMap _rootNames; public RootNameLookup() { } public SerializedString findRootName(JavaType rootType, MapperConfig config) { return findRootName(rootType.getRawClass(), config); } public synchronized SerializedString findRootName(Class rootType, MapperConfig config) { ClassKey key = new ClassKey(rootType); if (_rootNames == null) { _rootNames = new LRUMap(20, 200); } else { SerializedString name = _rootNames.get(key); if (name != null) { return name; } } BasicBeanDescription beanDesc = (BasicBeanDescription) config.introspectClassAnnotations(rootType); AnnotationIntrospector intr = config.getAnnotationIntrospector(); AnnotatedClass ac = beanDesc.getClassInfo(); String nameStr = intr.findRootName(ac); // No answer so far? Let's just default to using simple class name if (nameStr == null) { // Should we strip out enclosing class tho? For now, nope: nameStr = rootType.getSimpleName(); } SerializedString name = new SerializedString(nameStr); _rootNames.put(key, name); return name; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/LinkedNode.java0000644000175000017500000000217711655120726030045 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; /** * Node of a forward-only linked list. * * @author tatu * * @param Type of contained object */ public final class LinkedNode { final T _value; final LinkedNode _next; public LinkedNode(T value, LinkedNode next) { _value = value; _next = next; } public LinkedNode next() { return _next; } public T value() { return _value; } /** * Convenience method that can be used to check if a linked list * with given head node (which may be null to indicate empty list) * contains given value * * @param Type argument that defines contents of the linked list parameter * @param node Head node of the linked list * @param value Value to look for * @return True if linked list contains the value, false otherwise */ public static boolean contains(LinkedNode node, ST value) { while (node != null) { if (node.value() == value) { return true; } node = node.next(); } return false; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/JSONPObject.java0000644000175000017500000000651311655120726030047 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.type.JavaType; /** * Container class that can be used to wrap any Object instances (including * nulls), and will serialize embedded in * JSONP wrapping. * * @see org.codehaus.jackson.map.util.JSONWrappedObject * * @author tatu * @since 1.5 */ public class JSONPObject implements JsonSerializableWithType { /** * JSONP function name to use for serialization */ protected final String _function; /** * Value to be serialized as JSONP padded; can be null. */ protected final Object _value; /** * Optional static type to use for serialization; if null, runtime * type is used. Can be used to specify declared type which defines * serializer to use, as well as aspects of extra type information * to include (if any). */ protected final JavaType _serializationType; public JSONPObject(String function, Object value) { this(function, value, (JavaType) null); } public JSONPObject(String function, Object value, JavaType asType) { _function = function; _value = value; _serializationType = asType; } /** * @deprecated Since 1.8; instead use variant that takes JavaType: this ensures * that type information is properly resolved */ @Deprecated public JSONPObject(String function, Object value, Class rawType) { _function = function; _value = value; _serializationType = (rawType == null) ? null : TypeFactory.defaultInstance().constructType(rawType); } /* /********************************************************** /* JsonSerializable(WithType) implementation /********************************************************** */ @Override public void serializeWithType(JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { // No type for JSONP wrapping: value serializer will handle typing for value: serialize(jgen, provider); } @Override @SuppressWarnings("deprecation") public void serialize(JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { // First, wrapping: jgen.writeRaw(_function); jgen.writeRaw('('); if (_value == null) { provider.defaultSerializeNull(jgen); } else if (_serializationType != null) { provider.findTypedValueSerializer(_serializationType, true, null).serialize(_value, jgen, provider); } else { Class cls = _value.getClass(); provider.findTypedValueSerializer(cls, true, null).serialize(_value, jgen, provider); } jgen.writeRaw(')'); } /* /************************************************************** /* Accessors /************************************************************** */ public String getFunction() { return _function; } public Object getValue() { return _value; } public JavaType getSerializationType() { return _serializationType; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/Comparators.java0000644000175000017500000000320511655120726030314 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.lang.reflect.Array; /** * Helper class for constructing objects for comparing content values * * @since 1.9.0 */ public class Comparators { /** * Helper method used for constructing simple value comparator used for * comparing arrays for content equality. *

* Note: current implementation is not optimized for speed; if performance * ever becomes an issue, it is possible to construct much more efficient * typed instances (one for Object[] and sub-types; one per primitive type) * * @since 1.9 */ public static Object getArrayComparator(final Object defaultValue) { final int length = Array.getLength(defaultValue); return new Object() { @Override public boolean equals(Object other) { if (other == this) return true; if (other == null || other.getClass() != defaultValue.getClass()) { return false; } if (Array.getLength(other) != length) return false; // so far so good: compare actual equality; but only shallow one for (int i = 0; i < length; ++i) { Object value1 = Array.get(defaultValue, i); Object value2 = Array.get(other, i); if (value1 == value2) continue; if (value1 != null) { if (!value1.equals(value2)) { return false; } } } return true; } }; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/BeanUtil.java0000644000175000017500000002146611655120726027536 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import org.codehaus.jackson.map.introspect.AnnotatedMethod; /** * Helper class that contains functionality needed by both serialization * and deserialization side. * * @since 1.9 */ public class BeanUtil { /* * Helper method to use for sorting bean properties, based on * ordering rules indicated by annotations, config features. * * @param config Serialization/Deserialization configuration in effect * @param beanDesc Bean description * @param props Properties to sort if/as necessary * @param defaultSortByAlpha Whether properties should be (re)sorted alphabetically * by default (unless overridden by type) */ /* public static List sortProperties(MapperConfig config, BasicBeanDescription beanDesc, List props, boolean defaultSortByAlpha) { // First, order by [JACKSON-90] (explicit ordering and/or alphabetic) // and then for [JACKSON-170] (implicitly order creator properties before others) List creatorProps = beanDesc.findCreatorPropertyNames(); // Then how about explicit ordering? AnnotationIntrospector intr = config.getAnnotationIntrospector(); AnnotatedClass ac = beanDesc.getClassInfo(); String[] propertyOrder = intr.findSerializationPropertyOrder(ac); Boolean alpha = intr.findSerializationSortAlphabetically(ac); boolean sort; if (alpha == null) { sort = defaultSortByAlpha; } else { sort = alpha.booleanValue(); } // no sorting? no need to shuffle, then if (!sort && creatorProps.isEmpty() && propertyOrder == null) { return props; } int size = props.size(); Map all; // Need to (re)sort alphabetically? if (sort) { all = new TreeMap(); } else { all = new LinkedHashMap(size+size); } for (T w : props) { all.put(w.getName(), w); } Map ordered = new LinkedHashMap(size+size); // Ok: primarily by explicit order if (propertyOrder != null) { for (String name : propertyOrder) { T w = all.get(name); if (w != null) { ordered.put(name, w); } } } // And secondly by sorting Creator properties before other unordered properties for (String name : creatorProps) { T w = all.get(name); if (w != null) { ordered.put(name, w); } } // And finally whatever is left (trying to put again will not change ordering) ordered.putAll(all); return new ArrayList(ordered.values()); } */ /* /********************************************************** /* Handling "getter" names /********************************************************** */ public static String okNameForGetter(AnnotatedMethod am) { String name = am.getName(); String str = okNameForIsGetter(am, name); if (str == null) { str = okNameForRegularGetter(am, name); } return str; } public static String okNameForRegularGetter(AnnotatedMethod am, String name) { if (name.startsWith("get")) { /* 16-Feb-2009, tatu: To handle [JACKSON-53], need to block * CGLib-provided method "getCallbacks". Not sure of exact * safe criteria to get decent coverage without false matches; * but for now let's assume there's no reason to use any * such getter from CGLib. * But let's try this approach... */ if ("getCallbacks".equals(name)) { if (isCglibGetCallbacks(am)) { return null; } } else if ("getMetaClass".equals(name)) { /* 30-Apr-2009, tatu: [JACKSON-103], need to suppress * serialization of a cyclic (and useless) reference */ if (isGroovyMetaClassGetter(am)) { return null; } } return manglePropertyName(name.substring(3)); } return null; } public static String okNameForIsGetter(AnnotatedMethod am, String name) { if (name.startsWith("is")) { // plus, must return boolean... Class rt = am.getRawType(); if (rt != Boolean.class && rt != Boolean.TYPE) { return null; } return manglePropertyName(name.substring(2)); } // no, not a match by name return null; } public static String okNameForSetter(AnnotatedMethod am) { String name = am.getName(); if (name.startsWith("set")) { name = manglePropertyName(name.substring(3)); if (name == null) { // plain old "set" is no good... return null; } if ("metaClass".equals(name)) { // 26-Nov-2009 [JACSON-103], need to suppress this internal groovy method if (isGroovyMetaClassSetter(am)) { return null; } } return name; } return null; } /* /********************************************************** /* Helper methods for bean property name handling /********************************************************** */ /** * This method was added to address [JACKSON-53]: need to weed out * CGLib-injected "getCallbacks". * At this point caller has detected a potential getter method * with name "getCallbacks" and we need to determine if it is * indeed injectect by Cglib. We do this by verifying that the * result type is "net.sf.cglib.proxy.Callback[]" *

* Also, see [JACKSON-177]; Hibernate may repackage cglib * it uses, so we better catch that too */ protected static boolean isCglibGetCallbacks(AnnotatedMethod am) { Class rt = am.getRawType(); // Ok, first: must return an array type if (rt == null || !rt.isArray()) { return false; } /* And that type needs to be "net.sf.cglib.proxy.Callback". * Theoretically could just be a type that implements it, but * for now let's keep things simple, fix if need be. */ Class compType = rt.getComponentType(); // Actually, let's just verify it's a "net.sf.cglib.*" class/interface Package pkg = compType.getPackage(); if (pkg != null) { String pname = pkg.getName(); if (pname.startsWith("net.sf.cglib") // also, as per [JACKSON-177] || pname.startsWith("org.hibernate.repackage.cglib")) { return true; } } return false; } /** * Similar to {@link #isCglibGetCallbacks}, need to suppress * a cyclic reference to resolve [JACKSON-103] */ protected static boolean isGroovyMetaClassSetter(AnnotatedMethod am) { Class argType = am.getParameterClass(0); Package pkg = argType.getPackage(); if (pkg != null && pkg.getName().startsWith("groovy.lang")) { return true; } return false; } /** * Another helper method to deal with rest of [JACKSON-103] */ protected static boolean isGroovyMetaClassGetter(AnnotatedMethod am) { Class rt = am.getRawType(); if (rt == null || rt.isArray()) { return false; } Package pkg = rt.getPackage(); if (pkg != null && pkg.getName().startsWith("groovy.lang")) { return true; } return false; } /** * Method called to figure out name of the property, given * corresponding suggested name based on a method or field name. * * @param basename Name of accessor/mutator method, not including prefix * ("get"/"is"/"set") */ protected static String manglePropertyName(String basename) { int len = basename.length(); // First things first: empty basename is no good if (len == 0) { return null; } // otherwise, lower case initial chars StringBuilder sb = null; for (int i = 0; i < len; ++i) { char upper = basename.charAt(i); char lower = Character.toLowerCase(upper); if (upper == lower) { break; } if (sb == null) { sb = new StringBuilder(basename); } sb.setCharAt(i, lower); } return (sb == null) ? basename : sb.toString(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/package-info.java0000644000175000017500000000012611655120726030345 0ustar jamespagejamespage/** * Utility classes for Mapper package. */ package org.codehaus.jackson.map.util; jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/JSONWrappedObject.java0000644000175000017500000000745111655120726031254 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.type.JavaType; /** * General-purpose wrapper class that can be used to decorate serialized * value with arbitrary literal prefix and suffix. This can be used for * example to construct arbitrary Javascript values (similar to how basic * function name and parenthesis are used with JSONP). * * @see org.codehaus.jackson.map.util.JSONPObject * * @author tatu * @since 1.5 */ public class JSONWrappedObject implements JsonSerializableWithType { /** * Literal String to output before serialized value. * Will not be quoted when serializing value. */ protected final String _prefix; /** * Literal String to output after serialized value. * Will not be quoted when serializing value. */ protected final String _suffix; /** * Value to be serialized as JSONP padded; can be null. */ protected final Object _value; /** * Optional static type to use for serialization; if null, runtime * type is used. Can be used to specify declared type which defines * serializer to use, as well as aspects of extra type information * to include (if any). */ protected final JavaType _serializationType; public JSONWrappedObject(String prefix, String suffix, Object value) { this(prefix, suffix, value, (JavaType) null); } public JSONWrappedObject(String prefix, String suffix, Object value, JavaType asType) { _prefix = prefix; _suffix = suffix; _value = value; _serializationType = asType; } /** * @deprecated Since 1.8; should construct with resolved JavaType, * to ensure type has been properly resolved */ @Deprecated public JSONWrappedObject(String prefix, String suffix, Object value, Class rawType) { _prefix = prefix; _suffix = suffix; _value = value; _serializationType = (rawType == null) ? null : TypeFactory.defaultInstance().constructType(rawType); } /* /************************************************************** /* JsonSerializable(WithType) implementation /************************************************************** */ @Override public void serializeWithType(JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { // No type for JSONP wrapping: value serializer will handle typing for value: serialize(jgen, provider); } @Override @SuppressWarnings("deprecation") public void serialize(JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { // First, wrapping: if (_prefix != null) jgen.writeRaw(_prefix); if (_value == null) { provider.defaultSerializeNull(jgen); } else if (_serializationType != null) { provider.findTypedValueSerializer(_serializationType, true, null).serialize(_value, jgen, provider); } else { Class cls = _value.getClass(); provider.findTypedValueSerializer(cls, true, null).serialize(_value, jgen, provider); } if (_suffix != null) jgen.writeRaw(_suffix); } /* /************************************************************** /* Accessors /************************************************************** */ public String getPrefix() { return _prefix; } public String getSuffix() { return _suffix; } public Object getValue() { return _value; } public JavaType getSerializationType() { return _serializationType; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/Provider.java0000644000175000017500000000072111655120726027614 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.util.*; /** * Simple helper class used for decoupling instantiation of * optionally loaded handlers, like deserializers and deserializers * for libraries that are only present on some platforms. * * @author tatu * * @param Type of objects provided */ public interface Provider { /** * Method used to request provider to provide entries it has */ public Collection provide(); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/ArrayBuilders.java0000644000175000017500000002052111655120726030572 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.lang.reflect.Array; import java.util.*; /** * Helper class that contains set of distinct builders for different * arrays of primitive values. It also provides trivially simple * reuse scheme, which assumes that caller knows not to use instances * concurrently (which works ok with primitive arrays since they can * not contain other non-primitive types). */ public final class ArrayBuilders { BooleanBuilder _booleanBuilder = null; // note: no need for char[] builder, assume they are Strings ByteBuilder _byteBuilder = null; ShortBuilder _shortBuilder = null; IntBuilder _intBuilder = null; LongBuilder _longBuilder = null; FloatBuilder _floatBuilder = null; DoubleBuilder _doubleBuilder = null; public ArrayBuilders() { } public BooleanBuilder getBooleanBuilder() { if (_booleanBuilder == null) { _booleanBuilder = new BooleanBuilder(); } return _booleanBuilder; } public ByteBuilder getByteBuilder() { if (_byteBuilder == null) { _byteBuilder = new ByteBuilder(); } return _byteBuilder; } public ShortBuilder getShortBuilder() { if (_shortBuilder == null) { _shortBuilder = new ShortBuilder(); } return _shortBuilder; } public IntBuilder getIntBuilder() { if (_intBuilder == null) { _intBuilder = new IntBuilder(); } return _intBuilder; } public LongBuilder getLongBuilder() { if (_longBuilder == null) { _longBuilder = new LongBuilder(); } return _longBuilder; } public FloatBuilder getFloatBuilder() { if (_floatBuilder == null) { _floatBuilder = new FloatBuilder(); } return _floatBuilder; } public DoubleBuilder getDoubleBuilder() { if (_doubleBuilder == null) { _doubleBuilder = new DoubleBuilder(); } return _doubleBuilder; } /* /********************************************************** /* Impl classes /********************************************************** */ public final static class BooleanBuilder extends PrimitiveArrayBuilder { public BooleanBuilder() { } @Override public final boolean[] _constructArray(int len) { return new boolean[len]; } } public final static class ByteBuilder extends PrimitiveArrayBuilder { public ByteBuilder() { } @Override public final byte[] _constructArray(int len) { return new byte[len]; } } public final static class ShortBuilder extends PrimitiveArrayBuilder { public ShortBuilder() { } @Override public final short[] _constructArray(int len) { return new short[len]; } } public final static class IntBuilder extends PrimitiveArrayBuilder { public IntBuilder() { } @Override public final int[] _constructArray(int len) { return new int[len]; } } public final static class LongBuilder extends PrimitiveArrayBuilder { public LongBuilder() { } @Override public final long[] _constructArray(int len) { return new long[len]; } } public final static class FloatBuilder extends PrimitiveArrayBuilder { public FloatBuilder() { } @Override public final float[] _constructArray(int len) { return new float[len]; } } public final static class DoubleBuilder extends PrimitiveArrayBuilder { public DoubleBuilder() { } @Override public final double[] _constructArray(int len) { return new double[len]; } } /* /********************************************************** /* Static helper methods /********************************************************** */ public static HashSet arrayToSet(T[] elements) { HashSet result = new HashSet(); if (elements != null) { for (T elem : elements) { result.add(elem); } } return result; } /** * Helper method for adding specified element to a List, but also * considering case where the List may not have been yet constructed * (that is, null is passed instead). * * @param list List to add to; may be null to indicate that a new * List is to be constructed * @param element Element to add to list * * @return List in which element was added; either list * (if it was not null), or a newly constructed List. */ public static List addToList(List list, T element) { if (list == null) { list = new ArrayList(); } list.add(element); return list; } /** * Helper method for constructing a new array that contains specified * element followed by contents of the given array. No checking is done * to see if element being inserted is duplicate. */ public static T[] insertInList(T[] array, T element) { int len = array.length; @SuppressWarnings("unchecked") T[] result = (T[]) Array.newInstance(array.getClass().getComponentType(), len+1); if (len > 0) { System.arraycopy(array, 0, result, 1, len); } result[0] = element; return result; } /** * Helper method for constructing a new array that contains specified * element followed by contents of the given array but never contains * duplicates. * If element already existed, one of two things happens: if the element * was already the first one in array, array is returned as is; but * if not, a new copy is created in which element has moved as the head. */ @SuppressWarnings("unchecked") public static T[] insertInListNoDup(T[] array, T element) { final int len = array.length; // First: see if the element already exists for (int ix = 0; ix < len; ++ix) { if (array[ix] == element) { // if at head already, return as is if (ix == 0) { return array; } // otherwise move things around T[] result = (T[]) Array.newInstance(array.getClass().getComponentType(), len); System.arraycopy(array, 0, result, 1, ix); array[0] = element; return result; } } // but if not, allocate new array, move T[] result = (T[]) Array.newInstance(array.getClass().getComponentType(), len+1); if (len > 0) { System.arraycopy(array, 0, result, 1, len); } result[0] = element; return result; } /** * Helper method for exposing contents of arrays using a read-only * iterator * * @since 1.7 */ public static Iterator arrayAsIterator(T[] array) { return new ArrayIterator(array); } public static Iterable arrayAsIterable(T[] array) { return new ArrayIterator(array); } /* /********************************************************** /* Helper classes /********************************************************** */ /** * Iterator implementation used to efficiently expose contents of an * Array as read-only iterator. * * @since 1.7 */ private final static class ArrayIterator implements Iterator, Iterable { private final T[] _array; private int _index; public ArrayIterator(T[] array) { _array = array; _index = 0; } @Override public boolean hasNext() { return _index < _array.length; } @Override public T next() { if (_index >= _array.length) { throw new NoSuchElementException(); } return _array[_index++]; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public Iterator iterator() { return this; } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/PrimitiveArrayBuilder.java0000644000175000017500000001222711655120726032304 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; /** * Base class for specialized primitive array builders. */ public abstract class PrimitiveArrayBuilder { /** * Let's start with small chunks; typical usage is for small arrays anyway. */ final static int INITIAL_CHUNK_SIZE = 12; /** * Also: let's expand by doubling up until 64k chunks (which is 16k entries for * 32-bit machines) */ final static int SMALL_CHUNK_SIZE = (1 << 14); /** * Let's limit maximum size of chunks we use; helps avoid excessive allocation * overhead for huge data sets. * For now, let's limit to quarter million entries, 1 meg chunks for 32-bit * machines. */ final static int MAX_CHUNK_SIZE = (1 << 18); // // // Data storage T _freeBuffer; Node _bufferHead; Node _bufferTail; /** * Number of total buffered entries in this buffer, counting all instances * within linked list formed by following {@link #_bufferHead}. */ int _bufferedEntryCount; // // // Recycled instances of sub-classes // // // Life-cycle protected PrimitiveArrayBuilder() { } /* //////////////////////////////////////////////////////////////////////// // Public API //////////////////////////////////////////////////////////////////////// */ public T resetAndStart() { _reset(); return (_freeBuffer == null) ? _constructArray(INITIAL_CHUNK_SIZE) : _freeBuffer; } /** * @return Length of the next chunk to allocate */ public final T appendCompletedChunk(T fullChunk, int fullChunkLength) { Node next = new Node(fullChunk, fullChunkLength); if (_bufferHead == null) { // first chunk _bufferHead = _bufferTail = next; } else { // have something already _bufferTail.linkNext(next); _bufferTail = next; } _bufferedEntryCount += fullChunkLength; int nextLen = fullChunkLength; // start with last chunk size // double the size for small chunks if (nextLen < SMALL_CHUNK_SIZE) { nextLen += nextLen; } else { // but by +25% for larger (to limit overhead) nextLen += (nextLen >> 2); } return _constructArray(nextLen); } public T completeAndClearBuffer(T lastChunk, int lastChunkEntries) { int totalSize = lastChunkEntries + _bufferedEntryCount; T resultArray = _constructArray(totalSize); int ptr = 0; for (Node n = _bufferHead; n != null; n = n.next()) { ptr = n.copyData(resultArray, ptr); } System.arraycopy(lastChunk, 0, resultArray, ptr, lastChunkEntries); ptr += lastChunkEntries; // sanity check (could have failed earlier due to out-of-bounds, too) if (ptr != totalSize) { throw new IllegalStateException("Should have gotten "+totalSize+" entries, got "+ptr); } return resultArray; } /* //////////////////////////////////////////////////////////////////////// // Abstract methods for sub-classes to implement //////////////////////////////////////////////////////////////////////// */ protected abstract T _constructArray(int len); /* //////////////////////////////////////////////////////////////////////// // Internal methods //////////////////////////////////////////////////////////////////////// */ protected void _reset() { // can we reuse the last (and thereby biggest) array for next time? if (_bufferTail != null) { _freeBuffer = _bufferTail.getData(); } // either way, must discard current contents _bufferHead = _bufferTail = null; _bufferedEntryCount = 0; } /* //////////////////////////////////////////////////////////////////////// // Helper classes //////////////////////////////////////////////////////////////////////// */ /** * For actual buffering beyond the current buffer, we can actually * use shared class which only deals with opaque "untyped" chunks. * This works because {@link java.lang.System#arraycopy} does not * take type; hence we can implement some aspects of primitive data * handling in generic fashion. */ final static class Node { /** * Data stored in this node. */ final T _data; /** * Number entries in the (untyped) array. Offset is assumed to be 0. */ final int _dataLength; Node _next; public Node(T data, int dataLen) { _data = data; _dataLength = dataLen; } public T getData() { return _data; } public int copyData(T dst, int ptr) { System.arraycopy(_data, 0, dst, ptr, _dataLength); ptr += _dataLength; return ptr; } public Node next() { return _next; } public void linkNext(Node next) { if (_next != null) { // sanity check throw new IllegalStateException(); } _next = next; } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/EnumResolver.java0000644000175000017500000000643511655120726030460 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import org.codehaus.jackson.map.AnnotationIntrospector; import java.util.*; /** * Helper class used to resolve String values (either JSON Object field * names or regular String values) into Java Enum instances. * * @since 1.9 renamed from 'org.codehaus.jackson.map.deser.EnumResolver' */ public class EnumResolver> { protected final Class _enumClass; protected final T[] _enums; protected final HashMap _enumsById; protected EnumResolver(Class enumClass, T[] enums, HashMap map) { _enumClass = enumClass; _enums = enums; _enumsById = map; } /** * Factory method for constructing resolver that maps from Enum.name() into * Enum value */ public static > EnumResolver constructFor(Class enumCls, AnnotationIntrospector ai) { ET[] enumValues = enumCls.getEnumConstants(); if (enumValues == null) { throw new IllegalArgumentException("No enum constants for class "+enumCls.getName()); } HashMap map = new HashMap(); for (ET e : enumValues) { map.put(ai.findEnumValue(e), e); } return new EnumResolver(enumCls, enumValues, map); } /** * Factory method for constructing resolver that maps from Enum.toString() into * Enum value * * @since 1.6 */ public static > EnumResolver constructUsingToString(Class enumCls) { ET[] enumValues = enumCls.getEnumConstants(); HashMap map = new HashMap(); // from last to first, so that in case of duplicate values, first wins for (int i = enumValues.length; --i >= 0; ) { ET e = enumValues[i]; map.put(e.toString(), e); } return new EnumResolver(enumCls, enumValues, map); } /** * This method is needed because of the dynamic nature of constructing Enum * resolvers. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static EnumResolver constructUnsafe(Class rawEnumCls, AnnotationIntrospector ai) { /* This is oh so wrong... but at least ugliness is mostly hidden in just * this one place. */ Class enumCls = (Class) rawEnumCls; return constructFor(enumCls, ai); } /** * Method that needs to be used instead of {@link #constructUsingToString} * if static type of enum is not known. * * @since 1.6 */ @SuppressWarnings({ "unchecked", "rawtypes" }) public static EnumResolver constructUnsafeUsingToString(Class rawEnumCls) { // oh so wrong... not much that can be done tho Class enumCls = (Class) rawEnumCls; return constructUsingToString(enumCls); } public T findEnum(String key) { return _enumsById.get(key); } public T getEnum(int index) { if (index < 0 || index >= _enums.length) { return null; } return _enums[index]; } public Class getEnumClass() { return _enumClass; } public int lastValidIndex() { return _enums.length-1; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/EnumValues.java0000644000175000017500000000526211655120726030113 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.util.*; import org.codehaus.jackson.io.SerializedString; import org.codehaus.jackson.map.*; /** * Helper class used for storing String serializations of * enumerations. */ public final class EnumValues { /** * Since 1.7, we are storing values as SerializedStrings, to further * speed up serialization. */ private final EnumMap _values; @SuppressWarnings({ "unchecked", "rawtypes" }) private EnumValues(Map,SerializedString> v) { _values = new EnumMap(v); } public static EnumValues construct(Class> enumClass, AnnotationIntrospector intr) { return constructFromName(enumClass, intr); } public static EnumValues constructFromName(Class> enumClass, AnnotationIntrospector intr) { /* [JACKSON-214]: Enum types with per-instance sub-classes * need special handling */ Class> cls = ClassUtil.findEnumType(enumClass); Enum[] values = cls.getEnumConstants(); if (values != null) { // Type juggling... unfortunate Map,SerializedString> map = new HashMap,SerializedString>(); for (Enum en : values) { String value = intr.findEnumValue(en); map.put(en, new SerializedString(value)); } return new EnumValues(map); } throw new IllegalArgumentException("Can not determine enum constants for Class "+enumClass.getName()); } public static EnumValues constructFromToString(Class> enumClass, AnnotationIntrospector intr) { Class> cls = ClassUtil.findEnumType(enumClass); Enum[] values = cls.getEnumConstants(); if (values != null) { // Type juggling... unfortunate Map,SerializedString> map = new HashMap,SerializedString>(); for (Enum en : values) { map.put(en, new SerializedString(en.toString())); } return new EnumValues(map); } throw new IllegalArgumentException("Can not determine enum constants for Class "+enumClass.getName()); } /** * @deprecated since 1.7, use {@link #serializedValueFor} instead */ @Deprecated public String valueFor(Enum key) { SerializedString sstr = _values.get(key); return (sstr == null) ? null : sstr.getValue(); } public SerializedString serializedValueFor(Enum key) { return _values.get(key); } public Collection values() { return _values.values(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/ObjectBuffer.java0000644000175000017500000001740411655120726030370 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.lang.reflect.Array; import java.util.List; /** * Helper class to use for constructing Object arrays by appending entries * to create arrays of various lengths (length that is not known a priori). */ public final class ObjectBuffer { // // // Config constants /** * Let's start with small chunks; typical usage is for small arrays anyway. */ final static int INITIAL_CHUNK_SIZE = 12; /** * Also: let's expand by doubling up until 64k chunks (which is 16k entries for * 32-bit machines) */ final static int SMALL_CHUNK_SIZE = (1 << 14); /** * Let's limit maximum size of chunks we use; helps avoid excessive allocation * overhead for huge data sets. * For now, let's limit to quarter million entries, 1 meg chunks for 32-bit * machines. */ final static int MAX_CHUNK_SIZE = (1 << 18); // // // Data storage private Node _bufferHead; private Node _bufferTail; /** * Number of total buffered entries in this buffer, counting all instances * within linked list formed by following {@link #_bufferHead}. */ private int _bufferedEntryCount; // // // Simple reuse /** * Reusable Object array, stored here after buffer has been released having * been used previously. */ private Object[] _freeBuffer; /* /********************************************************** /* Construction /********************************************************** */ public ObjectBuffer() { } /* /********************************************************** /* Public API /********************************************************** */ /** * Method called to start buffering process. Will ensure that the buffer * is empty, and then return an object array to start chunking content on */ public Object[] resetAndStart() { _reset(); if (_freeBuffer == null) { return new Object[INITIAL_CHUNK_SIZE]; } return _freeBuffer; } /** * Method called to add a full Object array as a chunk buffered within * this buffer, and to obtain a new array to fill. Caller is not to use * the array it gives; but to use the returned array for continued * buffering. * * @param fullChunk Completed chunk that the caller is requesting * to append to this buffer. It is generally chunk that was * returned by an earlier call to {@link #resetAndStart} or * {@link #appendCompletedChunk} (although this is not required or * enforced) * * @return New chunk buffer for caller to fill */ public Object[] appendCompletedChunk(Object[] fullChunk) { Node next = new Node(fullChunk); if (_bufferHead == null) { // first chunk _bufferHead = _bufferTail = next; } else { // have something already _bufferTail.linkNext(next); _bufferTail = next; } int len = fullChunk.length; _bufferedEntryCount += len; // double the size for small chunks if (len < SMALL_CHUNK_SIZE) { len += len; } else { // but by +25% for larger (to limit overhead) len += (len >> 2); } return new Object[len]; } /** * Method called to indicate that the buffering process is now * complete; and to construct a combined exactly-sized result * array. Additionally the buffer itself will be reset to * reduce memory retention. *

* Resulting array will be of generic Object[] type: * if a typed array is needed, use the method with additional * type argument. */ public Object[] completeAndClearBuffer(Object[] lastChunk, int lastChunkEntries) { int totalSize = lastChunkEntries + _bufferedEntryCount; Object[] result = new Object[totalSize]; _copyTo(result, totalSize, lastChunk, lastChunkEntries); return result; } /** * Type-safe alternative to * {@link #completeAndClearBuffer(Object[], int)}, to allow * for constructing explicitly typed result array. * * @param componentType Type of elements included in the buffer. Will be * used for constructing the result array. */ public T[] completeAndClearBuffer(Object[] lastChunk, int lastChunkEntries, Class componentType) { int totalSize = lastChunkEntries + _bufferedEntryCount; @SuppressWarnings("unchecked") T[] result = (T[]) Array.newInstance(componentType, totalSize); _copyTo(result, totalSize, lastChunk, lastChunkEntries); _reset(); return result; } /** * Another * * @since 1.6 */ public void completeAndClearBuffer(Object[] lastChunk, int lastChunkEntries, List resultList) { for (Node n = _bufferHead; n != null; n = n.next()) { Object[] curr = n.getData(); for (int i = 0, len = curr.length; i < len; ++i) { resultList.add(curr[i]); } } // and then the last one for (int i = 0; i < lastChunkEntries; ++i) { resultList.add(lastChunk[i]); } } /** * Helper method that can be used to check how much free capacity * will this instance start with. Can be used to choose the best * instance to reuse, based on size of reusable object chunk * buffer holds reference to. */ public int initialCapacity() { return (_freeBuffer == null) ? 0 : _freeBuffer.length; } /** * Method that can be used to check how many Objects have been buffered * within this buffer. */ public int bufferedSize() { return _bufferedEntryCount; } /* /********************************************************** /* Internal methods /********************************************************** */ protected void _reset() { // can we reuse the last (and thereby biggest) array for next time? if (_bufferTail != null) { _freeBuffer = _bufferTail.getData(); } // either way, must discard current contents _bufferHead = _bufferTail = null; _bufferedEntryCount = 0; } protected final void _copyTo(Object resultArray, int totalSize, Object[] lastChunk, int lastChunkEntries) { int ptr = 0; for (Node n = _bufferHead; n != null; n = n.next()) { Object[] curr = n.getData(); int len = curr.length; System.arraycopy(curr, 0, resultArray, ptr, len); ptr += len; } System.arraycopy(lastChunk, 0, resultArray, ptr, lastChunkEntries); ptr += lastChunkEntries; // sanity check (could have failed earlier due to out-of-bounds, too) if (ptr != totalSize) { throw new IllegalStateException("Should have gotten "+totalSize+" entries, got "+ptr); } } /* /********************************************************** /* Helper classes /********************************************************** */ /** * Helper class used to store actual data, in a linked list. */ final static class Node { /** * Data stored in this node. Array is considered to be full. */ final Object[] _data; Node _next; public Node(Object[] data) { _data = data; } public Object[] getData() { return _data; } public Node next() { return _next; } public void linkNext(Node next) { if (_next != null) { // sanity check throw new IllegalStateException(); } _next = next; } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/ClassUtil.java0000644000175000017500000005124611655120726027735 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.lang.reflect.*; import java.util.*; public final class ClassUtil { /* /********************************************************** /* Methods that deal with inheritance /********************************************************** */ /** * Method that will find all sub-classes and implemented interfaces * of a given class or interface. Classes are listed in order of * precedence, starting with the immediate super-class, followed by * interfaces class directly declares to implemented, and then recursively * followed by parent of super-class and so forth. * Note that Object.class is not included in the list * regardless of whether endBefore argument is defined or not. * * @param endBefore Super-type to NOT include in results, if any; when * encountered, will be ignored (and no super types are checked). */ public static List> findSuperTypes(Class cls, Class endBefore) { return findSuperTypes(cls, endBefore, new ArrayList>(8)); } public static List> findSuperTypes(Class cls, Class endBefore, List> result) { _addSuperTypes(cls, endBefore, result, false); return result; } private static void _addSuperTypes(Class cls, Class endBefore, Collection> result, boolean addClassItself) { if (cls == endBefore || cls == null || cls == Object.class) { return; } if (addClassItself) { if (result.contains(cls)) { // already added, no need to check supers return; } result.add(cls); } for (Class intCls : cls.getInterfaces()) { _addSuperTypes(intCls, endBefore, result, true); } _addSuperTypes(cls.getSuperclass(), endBefore, result, true); } /* /********************************************************** /* Class type detection methods /********************************************************** */ /** * @return Null if class might be a bean; type String (that identifies * why it's not a bean) if not */ public static String canBeABeanType(Class type) { // First: language constructs that ain't beans: if (type.isAnnotation()) { return "annotation"; } if (type.isArray()) { return "array"; } if (type.isEnum()) { return "enum"; } if (type.isPrimitive()) { return "primitive"; } // Anything else? Seems valid, then return null; } /** * @deprecated since 1.9, use variant that takes second argument */ @Deprecated public static String isLocalType(Class type) { return isLocalType(type, false); } /** * @since 1.9 */ public static String isLocalType(Class type, boolean allowNonStatic) { /* As per [JACKSON-187], GAE seems to throw SecurityExceptions * here and there... and GAE itself has a bug, too * (see []). Bah. So we need to catch some wayward exceptions on GAE */ try { // one more: method locals, anonymous, are not good: if (type.getEnclosingMethod() != null) { return "local/anonymous"; } /* But how about non-static inner classes? Can't construct * easily (theoretically, we could try to check if parent * happens to be enclosing... but that gets convoluted) */ if (!allowNonStatic) { if (type.getEnclosingClass() != null) { if (!Modifier.isStatic(type.getModifiers())) { return "non-static member class"; } } } } catch (SecurityException e) { } catch (NullPointerException e) { } return null; } /** * Method for finding enclosing class for non-static inner classes * * @since 1.9 */ public static Class getOuterClass(Class type) { // as above, GAE has some issues... try { // one more: method locals, anonymous, are not good: if (type.getEnclosingMethod() != null) { return null; } if (!Modifier.isStatic(type.getModifiers())) { return type.getEnclosingClass(); } } catch (SecurityException e) { } catch (NullPointerException e) { } return null; } /** * Helper method used to weed out dynamic Proxy types; types that do * not expose concrete method API that we could use to figure out * automatic Bean (property) based serialization. */ public static boolean isProxyType(Class type) { // Then: well-known proxy (etc) classes if (Proxy.isProxyClass(type)) { return true; } String name = type.getName(); // Hibernate uses proxies heavily as well: if (name.startsWith("net.sf.cglib.proxy.") || name.startsWith("org.hibernate.proxy.")) { return true; } // Not one of known proxies, nope: return false; } /** * Helper method that checks if given class is a concrete one; * that is, not an interface or abstract class. */ public static boolean isConcrete(Class type) { int mod = type.getModifiers(); return (mod & (Modifier.INTERFACE | Modifier.ABSTRACT)) == 0; } /** * @since 1.6 */ public static boolean isConcrete(Member member) { int mod = member.getModifiers(); return (mod & (Modifier.INTERFACE | Modifier.ABSTRACT)) == 0; } public static boolean isCollectionMapOrArray(Class type) { if (type.isArray()) return true; if (Collection.class.isAssignableFrom(type)) return true; if (Map.class.isAssignableFrom(type)) return true; return false; } /* /********************************************************** /* Type name handling methods /********************************************************** */ /** * Helper method used to construct appropriate description * when passed either type (Class) or an instance; in latter * case, class of instance is to be used. */ public static String getClassDescription(Object classOrInstance) { if (classOrInstance == null) { return "unknown"; } Class cls = (classOrInstance instanceof Class) ? (Class) classOrInstance : classOrInstance.getClass(); return cls.getName(); } /* /********************************************************** /* Method type detection methods /********************************************************** */ public static boolean hasGetterSignature(Method m) { // First: static methods can't be getters if (Modifier.isStatic(m.getModifiers())) { return false; } // Must take no args Class[] pts = m.getParameterTypes(); if (pts != null && pts.length != 0) { return false; } // Can't be a void method if (Void.TYPE == m.getReturnType()) { return false; } // Otherwise looks ok: return true; } /* /********************************************************** /* Exception handling /********************************************************** */ /** * Method that can be used to find the "root cause", innermost * of chained (wrapped) exceptions. */ public static Throwable getRootCause(Throwable t) { while (t.getCause() != null) { t = t.getCause(); } return t; } /** * Method that will unwrap root causes of given Throwable, and throw * the innermost {@link Exception} or {@link Error} as is. * This is useful in cases where mandatory wrapping is added, which * is often done by Reflection API. * * @since 1.7 */ public static void throwRootCause(Throwable t) throws Exception { t = getRootCause(t); if (t instanceof Exception) { throw (Exception) t; } throw (Error) t; } /** * Method that will wrap 't' as an {@link IllegalArgumentException} if it * is a checked exception; otherwise (runtime exception or error) throw as is */ public static void throwAsIAE(Throwable t) { throwAsIAE(t, t.getMessage()); } /** * Method that will wrap 't' as an {@link IllegalArgumentException} (and with * specified message) if it * is a checked exception; otherwise (runtime exception or error) throw as is */ public static void throwAsIAE(Throwable t, String msg) { if (t instanceof RuntimeException) { throw (RuntimeException) t; } if (t instanceof Error) { throw (Error) t; } throw new IllegalArgumentException(msg, t); } /** * Method that will locate the innermost exception for given Throwable; * and then wrap it as an {@link IllegalArgumentException} if it * is a checked exception; otherwise (runtime exception or error) throw as is */ public static void unwrapAndThrowAsIAE(Throwable t) { throwAsIAE(getRootCause(t)); } /** * Method that will locate the innermost exception for given Throwable; * and then wrap it as an {@link IllegalArgumentException} if it * is a checked exception; otherwise (runtime exception or error) throw as is */ public static void unwrapAndThrowAsIAE(Throwable t, String msg) { throwAsIAE(getRootCause(t), msg); } /* /********************************************************** /* Instantiation /********************************************************** */ /** * Method that can be called to try to create an instantiate of * specified type. Instantiation is done using default no-argument * constructor. * * @param canFixAccess Whether it is possible to try to change access * rights of the default constructor (in case it is not publicly * accessible) or not. * * @throws IllegalArgumentException If instantiation fails for any reason; * except for cases where constructor throws an unchecked exception * (which will be passed as is) */ public static T createInstance(Class cls, boolean canFixAccess) throws IllegalArgumentException { Constructor ctor = findConstructor(cls, canFixAccess); if (ctor == null) { throw new IllegalArgumentException("Class "+cls.getName()+" has no default (no arg) constructor"); } try { return ctor.newInstance(); } catch (Exception e) { ClassUtil.unwrapAndThrowAsIAE(e, "Failed to instantiate class "+cls.getName()+", problem: "+e.getMessage()); return null; } } public static Constructor findConstructor(Class cls, boolean canFixAccess) throws IllegalArgumentException { try { Constructor ctor = cls.getDeclaredConstructor(); if (canFixAccess) { checkAndFixAccess(ctor); } else { // Has to be public... if (!Modifier.isPublic(ctor.getModifiers())) { throw new IllegalArgumentException("Default constructor for "+cls.getName()+" is not accessible (non-public?): not allowed to try modify access via Reflection: can not instantiate type"); } } return ctor; } catch (NoSuchMethodException e) { ; } catch (Exception e) { ClassUtil.unwrapAndThrowAsIAE(e, "Failed to find default constructor of class "+cls.getName()+", problem: "+e.getMessage()); } return null; } /* /********************************************************** /* Primitive type support /********************************************************** */ /** * Helper method used to get default value for wrappers used for primitive types * (0 for Integer etc) * * @since 1.6.1 */ public static Object defaultValue(Class cls) { if (cls == Integer.TYPE) { return Integer.valueOf(0); } if (cls == Long.TYPE) { return Long.valueOf(0L); } if (cls == Boolean.TYPE) { return Boolean.FALSE; } if (cls == Double.TYPE) { return Double.valueOf(0.0); } if (cls == Float.TYPE) { return Float.valueOf(0.0f); } if (cls == Byte.TYPE) { return Byte.valueOf((byte) 0); } if (cls == Short.TYPE) { return Short.valueOf((short) 0); } if (cls == Character.TYPE) { return '\0'; } throw new IllegalArgumentException("Class "+cls.getName()+" is not a primitive type"); } /** * Helper method for finding wrapper type for given primitive type (why isn't * there one in JDK?) * * @since 1.7.1 */ public static Class wrapperType(Class primitiveType) { if (primitiveType == Integer.TYPE) { return Integer.class; } if (primitiveType == Long.TYPE) { return Long.class; } if (primitiveType == Boolean.TYPE) { return Boolean.class; } if (primitiveType == Double.TYPE) { return Double.class; } if (primitiveType == Float.TYPE) { return Float.class; } if (primitiveType == Byte.TYPE) { return Byte.class; } if (primitiveType == Short.TYPE) { return Short.class; } if (primitiveType == Character.TYPE) { return Character.class; } throw new IllegalArgumentException("Class "+primitiveType.getName()+" is not a primitive type"); } /* /********************************************************** /* Access checking/handling methods /********************************************************** */ /** * Method called to check if we can use the passed method or constructor * (wrt access restriction -- public methods can be called, others * usually not); and if not, if there is a work-around for * the problem. */ public static void checkAndFixAccess(Member member) { // We know all members are also accessible objects... AccessibleObject ao = (AccessibleObject) member; /* 14-Jan-2009, tatu: It seems safe and potentially beneficial to * always to make it accessible (latter because it will force * skipping checks we have no use for...), so let's always call it. */ //if (!ao.isAccessible()) { try { ao.setAccessible(true); } catch (SecurityException se) { /* 17-Apr-2009, tatu: Related to [JACKSON-101]: this can fail on * platforms like EJB and Google App Engine); so let's * only fail if we really needed it... */ if (!ao.isAccessible()) { Class declClass = member.getDeclaringClass(); throw new IllegalArgumentException("Can not access "+member+" (from class "+declClass.getName()+"; failed to set access: "+se.getMessage()); } } //} } /* /********************************************************** /* Enum type detection /********************************************************** */ /** * Helper method that can be used to dynamically figure out * enumeration type of given {@link EnumSet}, without having * access to its declaration. * Code is needed to work around design flaw in JDK. * * @since 1.5 */ public static Class> findEnumType(EnumSet s) { // First things first: if not empty, easy to determine if (!s.isEmpty()) { return findEnumType(s.iterator().next()); } // Otherwise need to locate using an internal field return EnumTypeLocator.instance.enumTypeFor(s); } /** * Helper method that can be used to dynamically figure out * enumeration type of given {@link EnumSet}, without having * access to its declaration. * Code is needed to work around design flaw in JDK. * * @since 1.5 */ public static Class> findEnumType(EnumMap m) { if (!m.isEmpty()) { return findEnumType(m.keySet().iterator().next()); } // Otherwise need to locate using an internal field return EnumTypeLocator.instance.enumTypeFor(m); } /** * Helper method that can be used to dynamically figure out formal * enumeration type (class) for given enumeration. This is either * class of enum instance (for "simple" enumerations), or its * superclass (for enums with instance fields or methods) */ @SuppressWarnings("unchecked") public static Class> findEnumType(Enum en) { // enums with "body" are sub-classes of the formal type Class ec = en.getClass(); if (ec.getSuperclass() != Enum.class) { ec = ec.getSuperclass(); } return (Class>) ec; } /** * Helper method that can be used to dynamically figure out formal * enumeration type (class) for given class of an enumeration value. * This is either class of enum instance (for "simple" enumerations), * or its superclass (for enums with instance fields or methods) */ @SuppressWarnings("unchecked") public static Class> findEnumType(Class cls) { // enums with "body" are sub-classes of the formal type if (cls.getSuperclass() != Enum.class) { cls = cls.getSuperclass(); } return (Class>) cls; } /* /********************************************************** /* Helper classes /********************************************************** */ /** * Inner class used to contain gory details of how we can determine * details of instances of common JDK types like {@link EnumMap}s. */ private static class EnumTypeLocator { final static EnumTypeLocator instance = new EnumTypeLocator(); private final Field enumSetTypeField; private final Field enumMapTypeField; private EnumTypeLocator() { /* JDK uses following fields to store information about actual Enumeration * type for EnumSets, EnumMaps... */ enumSetTypeField = locateField(EnumSet.class, "elementType", Class.class); enumMapTypeField = locateField(EnumMap.class, "elementType", Class.class); } @SuppressWarnings("unchecked") public Class> enumTypeFor(EnumSet set) { if (enumSetTypeField != null) { return (Class>) get(set, enumSetTypeField); } throw new IllegalStateException("Can not figure out type for EnumSet (odd JDK platform?)"); } @SuppressWarnings("unchecked") public Class> enumTypeFor(EnumMap set) { if (enumMapTypeField != null) { return (Class>) get(set, enumMapTypeField); } throw new IllegalStateException("Can not figure out type for EnumMap (odd JDK platform?)"); } private Object get(Object bean, Field field) { try { return field.get(bean); } catch (Exception e) { throw new IllegalArgumentException(e); } } private static Field locateField(Class fromClass, String expectedName, Class type) { Field found = null; // First: let's see if we can find exact match: Field[] fields = fromClass.getDeclaredFields(); for (Field f : fields) { if (expectedName.equals(f.getName()) && f.getType() == type) { found = f; break; } } // And if not, if there is just one field with the type, that field if (found == null) { for (Field f : fields) { if (f.getType() == type) { // If more than one, can't choose if (found != null) return null; found = f; } } } if (found != null) { // it's non-public, need to force accessible try { found.setAccessible(true); } catch (Throwable t) { } } return found; } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/Annotations.java0000644000175000017500000000104711655120726030321 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.lang.annotation.Annotation; /** * Interface that defines interface for collection of annotations. *

* Standard mutable implementation is {@link org.codehaus.jackson.map.introspect.AnnotationMap} * * @since 1.7 */ public interface Annotations { /** * Main access method used to find value for given annotation. */ public A get(Class cls); /** * Returns number of annotation entries in this collection. */ public int size(); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/StdDateFormat.java0000644000175000017500000002732211655120726030531 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.text.DateFormat; import java.text.FieldPosition; import java.text.ParseException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.*; import org.codehaus.jackson.io.NumberInput; /** * Default {@link DateFormat} implementation used by standard Date * serializers and deserializers. For serialization defaults to using * an ISO-8601 compliant format (format String "yyyy-MM-dd'T'HH:mm:ss.SSSZ") * and for deserialization, both ISO-8601 and RFC-1123. */ @SuppressWarnings("serial") public class StdDateFormat extends DateFormat { /* TODO !!! 24-Nov-2009, tatu: Need to rewrite this class soon: * JDK date parsing is awfully brittle, and ISO-8601 is quite * permissive. The two don't mix, need to write a better one. */ /** * Defines a commonly used date format that conforms * to ISO-8601 date formatting standard, when it includes basic undecorated * timezone definition */ final static String DATE_FORMAT_STR_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; /** * Same as 'regular' 8601, but handles 'Z' as an alias for "+0000" * (or "GMT") */ final static String DATE_FORMAT_STR_ISO8601_Z = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; /** * ISO-8601 with just the Date part, no time * * @since 1.3.1 */ final static String DATE_FORMAT_STR_PLAIN = "yyyy-MM-dd"; /** * This constant defines the date format specified by * RFC 1123. */ final static String DATE_FORMAT_STR_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; /** * For error messages we'll also need a list of all formats. */ final static String[] ALL_FORMATS = new String[] { DATE_FORMAT_STR_ISO8601, DATE_FORMAT_STR_ISO8601_Z, DATE_FORMAT_STR_RFC1123, DATE_FORMAT_STR_PLAIN }; final static SimpleDateFormat DATE_FORMAT_RFC1123; final static SimpleDateFormat DATE_FORMAT_ISO8601; final static SimpleDateFormat DATE_FORMAT_ISO8601_Z; final static SimpleDateFormat DATE_FORMAT_PLAIN; /* Let's construct "blueprint" date format instances: can not be used * as is, due to thread-safety issues, but can be used for constructing * actual instances more cheaply (avoids re-parsing). */ static { /* Another important thing: let's force use of GMT for * baseline DataFormat objects */ TimeZone gmt = TimeZone.getTimeZone("GMT"); DATE_FORMAT_RFC1123 = new SimpleDateFormat(DATE_FORMAT_STR_RFC1123); DATE_FORMAT_RFC1123.setTimeZone(gmt); DATE_FORMAT_ISO8601 = new SimpleDateFormat(DATE_FORMAT_STR_ISO8601); DATE_FORMAT_ISO8601.setTimeZone(gmt); DATE_FORMAT_ISO8601_Z = new SimpleDateFormat(DATE_FORMAT_STR_ISO8601_Z); DATE_FORMAT_ISO8601_Z.setTimeZone(gmt); DATE_FORMAT_PLAIN = new SimpleDateFormat(DATE_FORMAT_STR_PLAIN); DATE_FORMAT_PLAIN.setTimeZone(gmt); } /** * A singleton instance can be used for cloning purposes. */ public final static StdDateFormat instance = new StdDateFormat(); transient SimpleDateFormat _formatRFC1123; transient SimpleDateFormat _formatISO8601; transient SimpleDateFormat _formatISO8601_z; transient SimpleDateFormat _formatPlain; /* /********************************************************** /* Life cycle, accessing singleton "standard" formats /********************************************************** */ public StdDateFormat() { } @Override public StdDateFormat clone() { /* Since we always delegate all work to child DateFormat instances, * let's NOT call super.clone(); this is bit unusual, but makes * sense here to avoid unnecessary work. */ return new StdDateFormat(); } /** * Method for getting the globally shared DateFormat instance * that uses GMT timezone and can handle simple ISO-8601 * compliant date format. */ public static DateFormat getBlueprintISO8601Format() { return DATE_FORMAT_ISO8601; } /** * Method for getting a non-shared DateFormat instance * that uses specified timezone and can handle simple ISO-8601 * compliant date format. */ public static DateFormat getISO8601Format(TimeZone tz) { DateFormat df = (SimpleDateFormat) DATE_FORMAT_ISO8601.clone(); df.setTimeZone(tz); return df; } /** * Method for getting the globally shared DateFormat instance * that uses GMT timezone and can handle RFC-1123 * compliant date format. */ public static DateFormat getBlueprintRFC1123Format() { return DATE_FORMAT_RFC1123; } /** * Method for getting a non-shared DateFormat instance * that uses specific timezone and can handle RFC-1123 * compliant date format. */ public static DateFormat getRFC1123Format(TimeZone tz) { DateFormat df = (SimpleDateFormat) DATE_FORMAT_RFC1123.clone(); df.setTimeZone(tz); return df; } /* /********************************************************** /* Public API /********************************************************** */ @Override public Date parse(String dateStr) throws ParseException { dateStr = dateStr.trim(); ParsePosition pos = new ParsePosition(0); Date result = parse(dateStr, pos); if (result != null) { return result; } StringBuilder sb = new StringBuilder(); for (String f : ALL_FORMATS) { if (sb.length() > 0) { sb.append("\", \""); } else { sb.append('"'); } sb.append(f); } sb.append('"'); throw new ParseException (String.format("Can not parse date \"%s\": not compatible with any of standard forms (%s)", dateStr, sb.toString()), pos.getErrorIndex()); } @Override public Date parse(String dateStr, ParsePosition pos) { if (looksLikeISO8601(dateStr)) { // also includes "plain" return parseAsISO8601(dateStr, pos); } /* 14-Feb-2010, tatu: As per [JACKSON-236], better also * consider "stringified" simple time stamp */ int i = dateStr.length(); while (--i >= 0) { char ch = dateStr.charAt(i); if (ch < '0' || ch > '9') break; } if (i < 0) { // all digits if (NumberInput.inLongRange(dateStr, false)) { return new Date(Long.parseLong(dateStr)); } } // Otherwise, fall back to using RFC 1123 return parseAsRFC1123(dateStr, pos); } @Override public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) { if (_formatISO8601 == null) { _formatISO8601 = (SimpleDateFormat) DATE_FORMAT_ISO8601.clone(); } return _formatISO8601.format(date, toAppendTo, fieldPosition); } /* /********************************************************** /* Helper methods /********************************************************** */ /** * Overridable helper method used to figure out which of supported * formats is the likeliest match. */ protected boolean looksLikeISO8601(String dateStr) { if (dateStr.length() >= 5 && Character.isDigit(dateStr.charAt(0)) && Character.isDigit(dateStr.charAt(3)) && dateStr.charAt(4) == '-' ) { return true; } return false; } protected Date parseAsISO8601(String dateStr, ParsePosition pos) { /* 21-May-2009, tatu: SimpleDateFormat has very strict handling of * timezone modifiers for ISO-8601. So we need to do some scrubbing. */ /* First: do we have "zulu" format ('Z' == "GMT")? If yes, that's * quite simple because we already set date format timezone to be * GMT, and hence can just strip out 'Z' altogether */ int len = dateStr.length(); char c = dateStr.charAt(len-1); SimpleDateFormat df; // [JACKSON-200]: need to support "plain" date... if (len <= 10 && Character.isDigit(c)) { df = _formatPlain; if (df == null) { df = _formatPlain = (SimpleDateFormat) DATE_FORMAT_PLAIN.clone(); } } else if (c == 'Z') { df = _formatISO8601_z; if (df == null) { df = _formatISO8601_z = (SimpleDateFormat) DATE_FORMAT_ISO8601_Z.clone(); } // [JACKSON-334]: may be missing milliseconds... if so, add if (dateStr.charAt(len-4) == ':') { StringBuilder sb = new StringBuilder(dateStr); sb.insert(len-1, ".000"); dateStr = sb.toString(); } } else { // Let's see if we have timezone indicator or not... if (hasTimeZone(dateStr)) { c = dateStr.charAt(len-3); if (c == ':') { // remove optional colon // remove colon StringBuilder sb = new StringBuilder(dateStr); sb.delete(len-3, len-2); dateStr = sb.toString(); } else if (c == '+' || c == '-') { // missing minutes // let's just append '00' dateStr += "00"; } // [JACKSON-334]: may be missing milliseconds... if so, add len = dateStr.length(); // '+0000' (5 chars); should come after '.000' (4 chars) of milliseconds, so: c = dateStr.charAt(len-9); if (Character.isDigit(c)) { StringBuilder sb = new StringBuilder(dateStr); sb.insert(len-5, ".000"); dateStr = sb.toString(); } df = _formatISO8601; if (_formatISO8601 == null) { df = _formatISO8601 = (SimpleDateFormat) DATE_FORMAT_ISO8601.clone(); } } else { /* 24-Nov-2009, tatu: Ugh. This is getting pretty * ugly. Need to rewrite soon! */ // If not, plain date. Easiest to just patch 'Z' in the end? StringBuilder sb = new StringBuilder(dateStr); // And possible also millisecond part if missing int timeLen = len - dateStr.lastIndexOf('T') - 1; if (timeLen <= 8) { sb.append(".000"); } sb.append('Z'); dateStr = sb.toString(); df = _formatISO8601_z; if (df == null) { df = _formatISO8601_z = (SimpleDateFormat) DATE_FORMAT_ISO8601_Z.clone(); } } } return df.parse(dateStr, pos); } protected Date parseAsRFC1123(String dateStr, ParsePosition pos) { if (_formatRFC1123 == null) { _formatRFC1123 = (SimpleDateFormat) DATE_FORMAT_RFC1123.clone(); } return _formatRFC1123.parse(dateStr, pos); } private final static boolean hasTimeZone(String str) { // Only accept "+hh", "+hhmm" and "+hh:mm" (and with minus), so int len = str.length(); if (len >= 6) { char c = str.charAt(len-6); if (c == '+' || c == '-') return true; c = str.charAt(len-5); if (c == '+' || c == '-') return true; c = str.charAt(len-3); if (c == '+' || c == '-') return true; } return false; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/LRUMap.java0000644000175000017500000000111411655120726027117 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; import java.util.LinkedHashMap; import java.util.Map; /** * Helper for simple bounded LRU maps used for reusing lookup values. * * @since 1.7 */ @SuppressWarnings("serial") public class LRUMap extends LinkedHashMap { protected final int _maxEntries; public LRUMap(int initialEntries, int maxEntries) { super(initialEntries, 0.8f, true); _maxEntries = maxEntries; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > _maxEntries; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/util/Named.java0000644000175000017500000000026111655120726027045 0ustar jamespagejamespagepackage org.codehaus.jackson.map.util; /** * Simple tag interface mostly to allow sorting by name * * @since 1.9 */ public interface Named { public String getName(); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/0000755000175000017500000000000011672662540026061 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/NamedType.java0000644000175000017500000000246111655120726030611 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype; /** * Simple container class for types with optional logical name, used * as external identifier * * @author tatu * @since 1.5 */ public final class NamedType { protected final Class _class; protected final int _hashCode; protected String _name; public NamedType(Class c) { this(c, null); } public NamedType(Class c, String name) { _class = c; _hashCode = c.getName().hashCode(); setName(name); } public Class getType() { return _class; } public String getName() { return _name; } public void setName(String name) { _name = (name == null || name.length() == 0) ? null : name; } public boolean hasName() { return _name != null; } /** * Equality is defined based on class only, not on name */ @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o.getClass() != getClass()) return false; return _class == ((NamedType) o)._class; } @Override public int hashCode() { return _hashCode; } @Override public String toString() { return "[NamedType, class "+_class.getName()+", name: "+(_name == null ? "null" :("'"+_name+"'"))+"]"; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/0000755000175000017500000000000011672662540027022 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/StdTypeResolverBuilder.java0000644000175000017500000001452011655120726034310 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.util.Collection; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.jsontype.NamedType; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.map.jsontype.TypeResolverBuilder; import org.codehaus.jackson.type.JavaType; /** * Default {@link TypeResolverBuilder} implementation. * * @author tatu * @since 1.5 */ public class StdTypeResolverBuilder implements TypeResolverBuilder { // Configuration settings: protected JsonTypeInfo.Id _idType; protected JsonTypeInfo.As _includeAs; protected String _typeProperty; /** * @since 1.9 */ protected Class _defaultImpl; // Objects protected TypeIdResolver _customIdResolver; /* /********************************************************** /* Accessors /********************************************************** */ @Override public Class getDefaultImpl() { return _defaultImpl; } /* /********************************************************** /* Construction, initialization, actual building /********************************************************** */ public StdTypeResolverBuilder() { } @Override public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes) { // sanity checks if (idType == null) { throw new IllegalArgumentException("idType can not be null"); } _idType = idType; _customIdResolver = idRes; // Let's also initialize property name as per idType default _typeProperty = idType.getDefaultPropertyName(); return this; } @Override public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes, BeanProperty property) { TypeIdResolver idRes = idResolver(config, baseType, subtypes, true, false); switch (_includeAs) { case WRAPPER_ARRAY: return new AsArrayTypeSerializer(idRes, property); case PROPERTY: return new AsPropertyTypeSerializer(idRes, property, _typeProperty); case WRAPPER_OBJECT: return new AsWrapperTypeSerializer(idRes, property); case EXTERNAL_PROPERTY: return new AsExternalTypeSerializer(idRes, property, _typeProperty); } throw new IllegalStateException("Do not know how to construct standard type serializer for inclusion type: "+_includeAs); } @Override public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection subtypes, BeanProperty property) { TypeIdResolver idRes = idResolver(config, baseType, subtypes, false, true); // First, method for converting type info to type id: switch (_includeAs) { case WRAPPER_ARRAY: return new AsArrayTypeDeserializer(baseType, idRes, property, _defaultImpl); case PROPERTY: return new AsPropertyTypeDeserializer(baseType, idRes, property, _defaultImpl, _typeProperty); case WRAPPER_OBJECT: return new AsWrapperTypeDeserializer(baseType, idRes, property, _defaultImpl); case EXTERNAL_PROPERTY: return new AsExternalTypeDeserializer(baseType, idRes, property, _defaultImpl, _typeProperty); } throw new IllegalStateException("Do not know how to construct standard type serializer for inclusion type: "+_includeAs); } /* /********************************************************** /* Construction, configuration /********************************************************** */ @Override public StdTypeResolverBuilder inclusion(JsonTypeInfo.As includeAs) { if (includeAs == null) { throw new IllegalArgumentException("includeAs can not be null"); } _includeAs = includeAs; return this; } /** * Method for constructing an instance with specified type property name * (property name to use for type id when using "as-property" inclusion). */ @Override public StdTypeResolverBuilder typeProperty(String typeIdPropName) { // ok to have null/empty; will restore to use defaults if (typeIdPropName == null || typeIdPropName.length() == 0) { typeIdPropName = _idType.getDefaultPropertyName(); } _typeProperty = typeIdPropName; return this; } @Override public StdTypeResolverBuilder defaultImpl(Class defaultImpl) { _defaultImpl = defaultImpl; return this; } /* /********************************************************** /* Accessors /********************************************************** */ public String getTypeProperty() { return _typeProperty; } /* /********************************************************** /* Internal methods /********************************************************** */ /** * Helper method that will either return configured custom * type id resolver, or construct a standard resolver * given configuration. */ protected TypeIdResolver idResolver(MapperConfig config, JavaType baseType, Collection subtypes, boolean forSer, boolean forDeser) { // Custom id resolver? if (_customIdResolver != null) { return _customIdResolver; } if (_idType == null) { throw new IllegalStateException("Can not build, 'init()' not yet called"); } switch (_idType) { case CLASS: return new ClassNameIdResolver(baseType, config.getTypeFactory()); case MINIMAL_CLASS: return new MinimalClassNameIdResolver(baseType, config.getTypeFactory()); case NAME: return TypeNameIdResolver.construct(config, baseType, subtypes, forSer, forDeser); case CUSTOM: // need custom resolver... case NONE: // hmmh. should never get this far with 'none' } throw new IllegalStateException("Do not know how to construct standard type id resolver for idType: "+_idType); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/TypeNameIdResolver.java0000644000175000017500000001214111655120726033401 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.util.*; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.MapperConfig; import org.codehaus.jackson.map.introspect.BasicBeanDescription; import org.codehaus.jackson.map.jsontype.NamedType; import org.codehaus.jackson.type.JavaType; public class TypeNameIdResolver extends TypeIdResolverBase { /** * @since 1.8 */ protected final MapperConfig _config; /** * Mappings from class name to type id, used for serialization */ protected final HashMap _typeToId; /** * Mappings from type id to JavaType, used for deserialization */ protected final HashMap _idToType; protected TypeNameIdResolver(MapperConfig config, JavaType baseType, HashMap typeToId, HashMap idToType) { super(baseType, config.getTypeFactory()); _config = config; _typeToId = typeToId; _idToType = idToType; } public static TypeNameIdResolver construct(MapperConfig config, JavaType baseType, Collection subtypes, boolean forSer, boolean forDeser) { // sanity check if (forSer == forDeser) throw new IllegalArgumentException(); HashMap typeToId = null; HashMap idToType = null; if (forSer) { typeToId = new HashMap(); } if (forDeser) { idToType = new HashMap(); } if (subtypes != null) { for (NamedType t : subtypes) { /* no name? Need to figure out default; for now, let's just * use non-qualified class name */ Class cls = t.getType(); String id = t.hasName() ? t.getName() : _defaultTypeId(cls); if (forSer) { typeToId.put(cls.getName(), id); } if (forDeser) { /* 24-Feb-2011, tatu: [JACKSON-498] One more problem; sometimes * we have same name for multiple types; if so, use most specific * one. */ JavaType prev = idToType.get(id); if (prev != null) { // Can only override if more specific if (cls.isAssignableFrom(prev.getRawClass())) { // nope, more generic (or same) continue; } } idToType.put(id, config.constructType(cls)); } } } return new TypeNameIdResolver(config, baseType, typeToId, idToType); } @Override public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.NAME; } @Override public String idFromValue(Object value) { Class cls = value.getClass(); final String key = cls.getName(); String name; synchronized (_typeToId) { name = _typeToId.get(key); if (name == null) { // 24-Feb-2011, tatu: As per [JACKSON-498], may need to dynamically look up name // can either throw an exception, or use default name... if (_config.isAnnotationProcessingEnabled()) { BasicBeanDescription beanDesc = _config.introspectClassAnnotations(cls); name = _config.getAnnotationIntrospector().findTypeName(beanDesc.getClassInfo()); } if (name == null) { // And if still not found, let's choose default? name = _defaultTypeId(cls); } _typeToId.put(key, name); } } return name; } @Override public String idFromValueAndType(Object value, Class type) { return idFromValue(value); } @Override public JavaType typeFromId(String id) throws IllegalArgumentException { JavaType t = _idToType.get(id); /* Now: if no type is found, should we try to locate it by * some other means? (specifically, if in same package as base type, * could just try Class.forName) * For now let's not add any such workarounds; can add if need be */ return t; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append('[').append(getClass().getName()); sb.append("; id-to-type=").append(_idToType); sb.append(']'); return sb.toString(); } /* /********************************************************* /* Helper methods /********************************************************* */ /** * If no name was explicitly given for a class, we will just * use non-qualified class name */ protected static String _defaultTypeId(Class cls) { String n = cls.getName(); int ix = n.lastIndexOf('.'); return (ix < 0) ? n : n.substring(ix+1); } } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsPropertyTypeDeserializer.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsPropertyTypeDeserializer.0000644000175000017500000001251311655120726034336 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.util.JsonParserSequence; import org.codehaus.jackson.util.TokenBuffer; /** * Type deserializer used with {@link As#PROPERTY} * inclusion mechanism. * Uses regular form (additional key/value entry before actual data) * when typed object is expressed as JSON Object; otherwise behaves similar to how * {@link As#WRAPPER_ARRAY} works. * Latter is used if JSON representation is polymorphic * * @since 1.5 * @author tatu */ public class AsPropertyTypeDeserializer extends AsArrayTypeDeserializer { protected final String _typePropertyName; @Deprecated // since 1.9 public AsPropertyTypeDeserializer(JavaType bt, TypeIdResolver idRes, BeanProperty property, String typePropName) { this(bt, idRes, property, null, typePropName); } public AsPropertyTypeDeserializer(JavaType bt, TypeIdResolver idRes, BeanProperty property, Class defaultImpl, String typePropName) { super(bt, idRes, property, defaultImpl); _typePropertyName = typePropName; } @Override public As getTypeInclusion() { return As.PROPERTY; } @Override public String getPropertyName() { return _typePropertyName; } /** * This is the trickiest thing to handle, since property we are looking * for may be anywhere... */ @Override public Object deserializeTypedFromObject(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // but first, sanity check to ensure we have START_OBJECT or FIELD_NAME JsonToken t = jp.getCurrentToken(); if (t == JsonToken.START_OBJECT) { t = jp.nextToken(); } else if (t != JsonToken.FIELD_NAME) { throw ctxt.wrongTokenException(jp, JsonToken.START_OBJECT, "need JSON Object to contain As.PROPERTY type information (for class "+baseTypeName()+")"); } // Ok, let's try to find the property. But first, need token buffer... TokenBuffer tb = null; for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) { String name = jp.getCurrentName(); jp.nextToken(); // to point to the value if (_typePropertyName.equals(name)) { // gotcha! String typeId = jp.getText(); JsonDeserializer deser = _findDeserializer(ctxt, typeId); // deserializer should take care of closing END_OBJECT as well if (tb != null) { jp = JsonParserSequence.createFlattened(tb.asParser(jp), jp); } /* Must point to the next value; tb had no current, jp * pointed to VALUE_STRING: */ jp.nextToken(); // to skip past String value // deserializer should take care of closing END_OBJECT as well return deser.deserialize(jp, ctxt); } if (tb == null) { tb = new TokenBuffer(null); } tb.writeFieldName(name); tb.copyCurrentStructure(jp); } return _deserializeTypedUsingDefaultImpl(jp, ctxt, tb); } // off-lined to keep main method lean and meand... protected Object _deserializeTypedUsingDefaultImpl(JsonParser jp, DeserializationContext ctxt, TokenBuffer tb) throws IOException, JsonProcessingException { // As per [JACKSON-614], may have default implement to use if (_defaultImpl != null) { JsonDeserializer deser = _findDefaultImplDeserializer(ctxt); if (tb != null) { tb.writeEndObject(); jp = tb.asParser(jp); // must move to point to the first token: jp.nextToken(); } return deser.deserialize(jp, ctxt); } // if not, an error throw ctxt.wrongTokenException(jp, JsonToken.FIELD_NAME, "missing property '"+_typePropertyName+"' that is to contain type id (for class "+baseTypeName()+")"); } /* As per [JACKSON-352], also need to re-route "unknown" version. Need to think * this through bit more in future, but for now this does address issue and has * no negative side effects (at least within existing unit test suite). */ @Override public Object deserializeTypedFromAny(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { /* [JACKSON-387]: Sometimes, however, we get an array wrapper; specifically * when an array or list has been serialized with type information. */ if (jp.getCurrentToken() == JsonToken.START_ARRAY) { return super.deserializeTypedFromArray(jp, ctxt); } return deserializeTypedFromObject(jp, ctxt); } // These are fine from base class: //public Object deserializeTypedFromArray(JsonParser jp, DeserializationContext ctxt) //public Object deserializeTypedFromScalar(JsonParser jp, DeserializationContext ctxt) } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsExternalTypeDeserializer.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsExternalTypeDeserializer.0000644000175000017500000000240711655120726034275 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.type.JavaType; /** * Type deserializer used with {@link As#EXTERNAL_PROPERTY} inclusion mechanism. * Actual implementation may look bit strange since it depends on comprehensive * pre-processing done by {@link org.codehaus.jackson.map.deser.BeanDeserializer} * to basically transform external type id into structure that looks more like * "wrapper-array" style inclusion. This intermediate form is chosen to allow * supporting all possible JSON structures. * * @since 1.9 */ public class AsExternalTypeDeserializer extends AsArrayTypeDeserializer { protected final String _typePropertyName; public AsExternalTypeDeserializer(JavaType bt, TypeIdResolver idRes, BeanProperty property, Class defaultImpl, String typePropName) { super(bt, idRes, property, defaultImpl); _typePropertyName = typePropName; } @Override public As getTypeInclusion() { return As.EXTERNAL_PROPERTY; } @Override public String getPropertyName() { return _typePropertyName; } } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsExternalTypeSerializer.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsExternalTypeSerializer.ja0000644000175000017500000000741311655120726034301 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.jsontype.TypeIdResolver; /** * Type serializer that preferably embeds type information as an "external" * type property; embedded in enclosing JSON object. * Note that this serializer should only be used when value is being output * at JSON Object context; otherwise it can not work reliably, and will have * to revert operation similar to {@link AsPropertyTypeSerializer}. *

* Note that implementation of serialization is bit cumbersome as we must * serialized external type id AFTER object; this because callback only * occurs after field name has been written. * * @since 1.9 */ public class AsExternalTypeSerializer extends TypeSerializerBase { protected final String _typePropertyName; public AsExternalTypeSerializer(TypeIdResolver idRes, BeanProperty property, String propName) { super(idRes, property); _typePropertyName = propName; } @Override public String getPropertyName() { return _typePropertyName; } @Override public As getTypeInclusion() { return As.EXTERNAL_PROPERTY; } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { _writePrefix(value, jgen); } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { _writePrefix(value, jgen, type); } @Override public void writeTypePrefixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { _writePrefix(value, jgen); } @Override public void writeTypePrefixForArray(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { _writePrefix(value, jgen, type); } @Override public void writeTypePrefixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { _writePrefix(value, jgen); } @Override public void writeTypePrefixForScalar(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { _writePrefix(value, jgen, type); } @Override public void writeTypeSuffixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { _writeSuffix(value, jgen); } @Override public void writeTypeSuffixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { _writeSuffix(value, jgen); } @Override public void writeTypeSuffixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { _writeSuffix(value, jgen); } /* /********************************************************** /* Helper methods /********************************************************** */ protected final void _writePrefix(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeStartObject(); } protected final void _writePrefix(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { jgen.writeStartObject(); } protected final void _writeSuffix(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeEndObject(); jgen.writeStringField(_typePropertyName, _idResolver.idFromValue(value)); } } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsArrayTypeDeserializer.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsArrayTypeDeserializer.jav0000644000175000017500000000743211655120726034275 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.type.JavaType; /** * Type deserializer used with {@link As#WRAPPER_ARRAY} * inclusion mechanism. Simple since JSON structure used is always * the same, regardless of structure used for actual value: wrapping * is done using a 2-element JSON Array where type id is the first * element, and actual object data as second element. * * @author tatus */ public class AsArrayTypeDeserializer extends TypeDeserializerBase { @Deprecated // since 1.9 public AsArrayTypeDeserializer(JavaType bt, TypeIdResolver idRes, BeanProperty property) { this(bt, idRes, property, null); } public AsArrayTypeDeserializer(JavaType bt, TypeIdResolver idRes, BeanProperty property, Class defaultImpl) { super(bt, idRes, property, defaultImpl); } @Override public As getTypeInclusion() { return As.WRAPPER_ARRAY; } /** * Method called when actual object is serialized as JSON Array. */ @Override public Object deserializeTypedFromArray(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } /** * Method called when actual object is serialized as JSON Object */ @Override public Object deserializeTypedFromObject(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } @Override public Object deserializeTypedFromScalar(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } @Override public Object deserializeTypedFromAny(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } /* /*************************************************************** /* Internal methods /*************************************************************** */ /** * Method that handles type information wrapper, locates actual * subtype deserializer to use, and calls it to do actual * deserialization. */ private final Object _deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonDeserializer deser = _findDeserializer(ctxt, _locateTypeId(jp, ctxt)); Object value = deser.deserialize(jp, ctxt); // And then need the closing END_ARRAY if (jp.nextToken() != JsonToken.END_ARRAY) { throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "expected closing END_ARRAY after type information and deserialized value"); } return value; } protected final String _locateTypeId(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { if (!jp.isExpectedStartArrayToken()) { throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "need JSON Array to contain As.WRAPPER_ARRAY type information for class "+baseTypeName()); } // And then type id as a String if (jp.nextToken() != JsonToken.VALUE_STRING) { throw ctxt.wrongTokenException(jp, JsonToken.VALUE_STRING, "need JSON String that contains type id (for subtype of "+baseTypeName()+")"); } String result = jp.getText(); jp.nextToken(); return result; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/package-info.java0000644000175000017500000000040411655120726032203 0ustar jamespagejamespage/** * Package that contains standard implementations for * {@link org.codehaus.jackson.map.jsontype.TypeResolverBuilder} * and * {@link org.codehaus.jackson.map.jsontype.TypeIdResolver}. * * @since 1.5 */ package org.codehaus.jackson.map.jsontype.impl; ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsWrapperTypeDeserializer.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsWrapperTypeDeserializer.j0000644000175000017500000000704111655120726034304 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.*; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.type.JavaType; /** * Type deserializer used with {@link As#WRAPPER_OBJECT} * inclusion mechanism. Simple since JSON structure used is always * the same, regardless of structure used for actual value: wrapping * is done using a single-element JSON Object where type id is the key, * and actual object data as the value. * * @author tatus */ public class AsWrapperTypeDeserializer extends TypeDeserializerBase { @Deprecated // since 1.9 public AsWrapperTypeDeserializer(JavaType bt, TypeIdResolver idRes, BeanProperty property) { this(bt, idRes, property, null); } public AsWrapperTypeDeserializer(JavaType bt, TypeIdResolver idRes, BeanProperty property, Class defaultImpl) { super(bt, idRes, property, null); } @Override public As getTypeInclusion() { return As.WRAPPER_OBJECT; } /** * Deserializing type id enclosed using WRAPPER_OBJECT style is straightforward */ @Override public Object deserializeTypedFromObject(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } @Override public Object deserializeTypedFromArray(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } @Override public Object deserializeTypedFromScalar(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } @Override public Object deserializeTypedFromAny(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { return _deserialize(jp, ctxt); } /* /*************************************************************** /* Internal methods /*************************************************************** */ /** * Method that handles type information wrapper, locates actual * subtype deserializer to use, and calls it to do actual * deserialization. */ private final Object _deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // first, sanity checks if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw ctxt.wrongTokenException(jp, JsonToken.START_OBJECT, "need JSON Object to contain As.WRAPPER_OBJECT type information for class "+baseTypeName()); } // should always get field name, but just in case... if (jp.nextToken() != JsonToken.FIELD_NAME) { throw ctxt.wrongTokenException(jp, JsonToken.FIELD_NAME, "need JSON String that contains type id (for subtype of "+baseTypeName()+")"); } JsonDeserializer deser = _findDeserializer(ctxt, jp.getText()); jp.nextToken(); Object value = deser.deserialize(jp, ctxt); // And then need the closing END_OBJECT if (jp.nextToken() != JsonToken.END_OBJECT) { throw ctxt.wrongTokenException(jp, JsonToken.END_OBJECT, "expected closing END_OBJECT after type information and deserialized value"); } return value; } } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsPropertyTypeSerializer.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsPropertyTypeSerializer.ja0000644000175000017500000000456111655120726034344 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.jsontype.TypeIdResolver; /** * Type serializer that preferably embeds type information as an additional * JSON Object property, if possible (when resulting serialization would * use JSON Object). If this is not possible (for JSON Arrays, scalars), * uses a JSON Array wrapper (similar to how * {@link As#WRAPPER_ARRAY} always works) as a fallback. * * @since 1.5 * @author tatus */ public class AsPropertyTypeSerializer extends AsArrayTypeSerializer { protected final String _typePropertyName; public AsPropertyTypeSerializer(TypeIdResolver idRes, BeanProperty property, String propName) { super(idRes, property); _typePropertyName = propName; } @Override public String getPropertyName() { return _typePropertyName; } @Override public As getTypeInclusion() { return As.PROPERTY; } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeStartObject(); jgen.writeStringField(_typePropertyName, _idResolver.idFromValue(value)); } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { jgen.writeStartObject(); jgen.writeStringField(_typePropertyName, _idResolver.idFromValueAndType(value, type)); } //public void writeTypePrefixForArray(Object value, JsonGenerator jgen) //public void writeTypePrefixForArray(Object value, JsonGenerator jgen, Class type) //public void writeTypePrefixForScalar(Object value, JsonGenerator jgen) //public void writeTypePrefixForScalar(Object value, JsonGenerator jgen, Class type) @Override public void writeTypeSuffixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeEndObject(); } //public void writeTypeSuffixForArray(Object value, JsonGenerator jgen) //public void writeTypeSuffixForScalar(Object value, JsonGenerator jgen) } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/ClassNameIdResolver.java0000644000175000017500000001357211655120726033536 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.util.*; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.map.util.ClassUtil; /** * {@link org.codehaus.jackson.map.jsontype.TypeIdResolver} implementation * that converts between fully-qualified * Java class names and (JSON) Strings. */ public class ClassNameIdResolver extends TypeIdResolverBase { public ClassNameIdResolver(JavaType baseType, TypeFactory typeFactory) { super(baseType, typeFactory); } @Override public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.CLASS; } public void registerSubtype(Class type, String name) { // not used with class name - based resolvers } @Override public String idFromValue(Object value) { return _idFrom(value, value.getClass()); } @Override public String idFromValueAndType(Object value, Class type) { return _idFrom(value, type); } @Override public JavaType typeFromId(String id) { /* 30-Jan-2010, tatu: Most ids are basic class names; so let's first * check if any generics info is added; and only then ask factory * to do translation when necessary */ if (id.indexOf('<') > 0) { JavaType t = TypeFactory.fromCanonical(id); // note: may want to try combining with specialization (esp for EnumMap) return t; } try { /* [JACKSON-350]: Default Class.forName() won't work too well; context class loader * seems like slightly better choice */ // Class cls = Class.forName(id); ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class cls = Class.forName(id, true, loader); return _typeFactory.constructSpecializedType(_baseType, cls); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Invalid type id '"+id+"' (for id type 'Id.class'): no such class found"); } catch (Exception e) { throw new IllegalArgumentException("Invalid type id '"+id+"' (for id type 'Id.class'): "+e.getMessage(), e); } } /* /********************************************************** /* Internal methods /********************************************************** */ protected final String _idFrom(Object value, Class cls) { // [JACKSON-380] Need to ensure that "enum subtypes" work too if (Enum.class.isAssignableFrom(cls)) { if (!cls.isEnum()) { // means that it's sub-class of base enum, so: cls = cls.getSuperclass(); } } String str = cls.getName(); if (str.startsWith("java.util")) { /* 25-Jan-2009, tatu: There are some internal classes that * we can not access as is. We need better mechanism; for * now this has to do... */ /* Enum sets and maps are problematic since we MUST know * type of contained enums, to be able to deserialize. * In addition, EnumSet is not a concrete type either */ if (value instanceof EnumSet) { // Regular- and JumboEnumSet... Class enumClass = ClassUtil.findEnumType((EnumSet) value); // not optimal: but EnumSet is not a customizable type so this is sort of ok str = TypeFactory.defaultInstance().constructCollectionType(EnumSet.class, enumClass).toCanonical(); } else if (value instanceof EnumMap) { Class enumClass = ClassUtil.findEnumType((EnumMap) value); Class valueClass = Object.class; // not optimal: but EnumMap is not a customizable type so this is sort of ok str = TypeFactory.defaultInstance().constructMapType(EnumMap.class, enumClass, valueClass).toCanonical(); } else { String end = str.substring(9); if ((end.startsWith(".Arrays$") || end.startsWith(".Collections$")) && str.indexOf("List") >= 0) { /* 17-Feb-2010, tatus: Another such case: result of * Arrays.asList() is named like so in Sun JDK... * Let's just plain old ArrayList in its place * NOTE: chances are there are plenty of similar cases * for other wrappers... (immutable, singleton, synced etc) */ str = "java.util.ArrayList"; } } } else if (str.indexOf('$') >= 0) { /* Other special handling may be needed for inner classes, [JACKSON-584]. * The best way to handle would be to find 'hidden' constructor; pass parent * value etc (which is actually done for non-anonymous static classes!), * but that is just not possible due to various things. So, we will instead * try to generalize type into something we will be more likely to be able * construct. */ Class outer = ClassUtil.getOuterClass(cls); if (outer != null) { /* one more check: let's actually not worry if the declared * static type is non-static as well; if so, deserializer does * have a chance at figuring it all out. */ Class staticType = _baseType.getRawClass(); if (ClassUtil.getOuterClass(staticType) == null) { // Is this always correct? Seems like it should be... cls = _baseType.getRawClass(); str = cls.getName(); } } } return str; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/TypeDeserializerBase.java0000644000175000017500000001264011655120726033743 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import java.util.HashMap; import org.codehaus.jackson.*; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.DeserializationContext; import org.codehaus.jackson.map.JsonDeserializer; import org.codehaus.jackson.map.TypeDeserializer; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.type.JavaType; /** * @since 1.5 * @author tatus */ public abstract class TypeDeserializerBase extends TypeDeserializer { protected final TypeIdResolver _idResolver; protected final JavaType _baseType; protected final BeanProperty _property; /** * Type to use as the default implementation, if type id is * missing or can not be resolved. * * @since 1.9 */ protected final JavaType _defaultImpl; /** * For efficient operation we will lazily build mappings from type ids * to actual deserializers, once needed. */ protected final HashMap> _deserializers; /** * @since 1.9 */ protected JsonDeserializer _defaultImplDeserializer; /** * @deprecated Since 1.9, use the constructor that takes 'defaultImpl' */ @Deprecated protected TypeDeserializerBase(JavaType baseType, TypeIdResolver idRes, BeanProperty property) { this(baseType, idRes, property, null); } protected TypeDeserializerBase(JavaType baseType, TypeIdResolver idRes, BeanProperty property, Class defaultImpl) { _baseType = baseType; _idResolver = idRes; _property = property; _deserializers = new HashMap>(); if (defaultImpl == null) { _defaultImpl = null; } else { /* 16-Oct-2011, tatu: should call this via TypeFactory; this is * not entirely safe... however, since Collections/Maps are * seldom (if ever) base types, may be ok. */ _defaultImpl = baseType.forcedNarrowBy(defaultImpl); } } @Override public abstract JsonTypeInfo.As getTypeInclusion(); public String baseTypeName() { return _baseType.getRawClass().getName(); } @Override public String getPropertyName() { return null; } @Override public TypeIdResolver getTypeIdResolver() { return _idResolver; } @Override public Class getDefaultImpl() { return (_defaultImpl == null) ? null : _defaultImpl.getRawClass(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append('[').append(getClass().getName()); sb.append("; base-type:").append(_baseType); sb.append("; id-resolver: ").append(_idResolver); sb.append(']'); return sb.toString(); } /* /********************************************************** /* Helper methods for sub-classes /********************************************************** */ protected final JsonDeserializer _findDeserializer(DeserializationContext ctxt, String typeId) throws IOException, JsonProcessingException { JsonDeserializer deser; synchronized (_deserializers) { deser = _deserializers.get(typeId); if (deser == null) { JavaType type = _idResolver.typeFromId(typeId); if (type == null) { // As per [JACKSON-614], use the default impl if no type id available: if (_defaultImpl == null) { throw ctxt.unknownTypeException(_baseType, typeId); } deser = _findDefaultImplDeserializer(ctxt); } else { /* 16-Dec-2010, tatu: Since nominal type we get here has no (generic) type parameters, * we actually now need to explicitly narrow from base type (which may have parameterization) * using raw type. * * One complication, though; can not change 'type class' (simple type to container); otherwise * we may try to narrow a SimpleType (Object.class) into MapType (Map.class), losing actual * type in process (getting SimpleType of Map.class which will not work as expected) */ if (_baseType != null && _baseType.getClass() == type.getClass()) { type = _baseType.narrowBy(type.getRawClass()); } deser = ctxt.getDeserializerProvider().findValueDeserializer(ctxt.getConfig(), type, _property); } _deserializers.put(typeId, deser); } } return deser; } protected final JsonDeserializer _findDefaultImplDeserializer(DeserializationContext ctxt) throws IOException, JsonProcessingException { if (_defaultImpl == null) { return null; } synchronized (_defaultImpl) { if (_defaultImplDeserializer == null) { _defaultImplDeserializer = ctxt.getDeserializerProvider().findValueDeserializer(ctxt.getConfig(), _defaultImpl, _property); } return _defaultImplDeserializer; } } } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsWrapperTypeSerializer.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsWrapperTypeSerializer.jav0000644000175000017500000000740711655120726034330 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.jsontype.TypeIdResolver; /** * Type wrapper that tries to use an extra JSON Object, with a single * entry that has type name as key, to serialize type information. * If this is not possible (value is serialize as array or primitive), * will use {@link As#WRAPPER_ARRAY} mechanism as fallback: that is, * just use a wrapping array with type information as the first element * and value as second. * * @since 1.5 * @author tatus */ public class AsWrapperTypeSerializer extends TypeSerializerBase { public AsWrapperTypeSerializer(TypeIdResolver idRes, BeanProperty property) { super(idRes, property); } @Override public As getTypeInclusion() { return As.WRAPPER_OBJECT; } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // wrapper jgen.writeStartObject(); // and then JSON Object start caller wants jgen.writeObjectFieldStart(_idResolver.idFromValue(value)); } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { // wrapper jgen.writeStartObject(); // and then JSON Object start caller wants jgen.writeObjectFieldStart(_idResolver.idFromValueAndType(value, type)); } @Override public void writeTypePrefixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // can still wrap ok jgen.writeStartObject(); // and then JSON Array start caller wants jgen.writeArrayFieldStart(_idResolver.idFromValue(value)); } @Override public void writeTypePrefixForArray(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { // can still wrap ok jgen.writeStartObject(); // and then JSON Array start caller wants jgen.writeArrayFieldStart(_idResolver.idFromValueAndType(value, type)); } @Override public void writeTypePrefixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // can still wrap ok jgen.writeStartObject(); jgen.writeFieldName(_idResolver.idFromValue(value)); } @Override public void writeTypePrefixForScalar(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { // can still wrap ok jgen.writeStartObject(); jgen.writeFieldName(_idResolver.idFromValueAndType(value, type)); } @Override public void writeTypeSuffixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // first close JSON Object caller used jgen.writeEndObject(); // and then wrapper jgen.writeEndObject(); } @Override public void writeTypeSuffixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // first close array caller needed jgen.writeEndArray(); // then wrapper object jgen.writeEndObject(); } @Override public void writeTypeSuffixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // just need to close the wrapper object jgen.writeEndObject(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/StdSubtypeResolver.java0000644000175000017500000001370111655120726033513 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.util.*; import org.codehaus.jackson.map.AnnotationIntrospector; import org.codehaus.jackson.map.MapperConfig; import org.codehaus.jackson.map.introspect.*; import org.codehaus.jackson.map.jsontype.NamedType; import org.codehaus.jackson.map.jsontype.SubtypeResolver; /** * @since 1.5 */ public class StdSubtypeResolver extends SubtypeResolver { protected LinkedHashSet _registeredSubtypes; public StdSubtypeResolver() { } /* /********************************************************** /* Public API /********************************************************** */ @Override public void registerSubtypes(NamedType... types) { if (_registeredSubtypes == null) { _registeredSubtypes = new LinkedHashSet(); } for (NamedType type : types) { _registeredSubtypes.add(type); } } @Override public void registerSubtypes(Class... classes) { NamedType[] types = new NamedType[classes.length]; for (int i = 0, len = classes.length; i < len; ++i) { types[i] = new NamedType(classes[i]); } registerSubtypes(types); } /** * * @param property Base member to use for type resolution: either annotated type (class), * or property (field, getter/setter) */ @Override public Collection collectAndResolveSubtypes(AnnotatedMember property, MapperConfig config, AnnotationIntrospector ai) { HashMap collected = new HashMap(); // start with registered subtypes (which have precedence) if (_registeredSubtypes != null) { Class rawBase = property.getRawType(); for (NamedType subtype : _registeredSubtypes) { // is it a subtype of root type? if (rawBase.isAssignableFrom(subtype.getType())) { // yes AnnotatedClass curr = AnnotatedClass.constructWithoutSuperTypes(subtype.getType(), ai, config); _collectAndResolve(curr, subtype, config, ai, collected); } } } // then annotated types for property itself Collection st = ai.findSubtypes(property); if (st != null) { for (NamedType nt : st) { AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(nt.getType(), ai, config); _collectAndResolve(ac, nt, config, ai, collected); } } NamedType rootType = new NamedType(property.getRawType(), null); AnnotatedClass ac = AnnotatedClass.constructWithoutSuperTypes(property.getRawType(), ai, config); // and finally subtypes via annotations from base type (recursively) _collectAndResolve(ac, rootType, config, ai, collected); return new ArrayList(collected.values()); } @Override public Collection collectAndResolveSubtypes(AnnotatedClass type, MapperConfig config, AnnotationIntrospector ai) { HashMap subtypes = new HashMap(); // [JACKSON-257] then consider registered subtypes (which have precedence over annotations) if (_registeredSubtypes != null) { Class rawBase = type.getRawType(); for (NamedType subtype : _registeredSubtypes) { // is it a subtype of root type? if (rawBase.isAssignableFrom(subtype.getType())) { // yes AnnotatedClass curr = AnnotatedClass.constructWithoutSuperTypes(subtype.getType(), ai, config); _collectAndResolve(curr, subtype, config, ai, subtypes); } } } // and then check subtypes via annotations from base type (recursively) NamedType rootType = new NamedType(type.getRawType(), null); _collectAndResolve(type, rootType, config, ai, subtypes); return new ArrayList(subtypes.values()); } /* /********************************************************** /* Internal methods /********************************************************** */ /** * Method called to find subtypes for a specific type (class) */ protected void _collectAndResolve(AnnotatedClass annotatedType, NamedType namedType, MapperConfig config, AnnotationIntrospector ai, HashMap collectedSubtypes) { if (!namedType.hasName()) { String name = ai.findTypeName(annotatedType); if (name != null) { namedType = new NamedType(namedType.getType(), name); } } // First things first: is base type itself included? if (collectedSubtypes.containsKey(namedType)) { // if so, no recursion; however, may need to update name? if (namedType.hasName()) { NamedType prev = collectedSubtypes.get(namedType); if (!prev.hasName()) { collectedSubtypes.put(namedType, namedType); } } return; } // if it wasn't, add and check subtypes recursively collectedSubtypes.put(namedType, namedType); Collection st = ai.findSubtypes(annotatedType); if (st != null && !st.isEmpty()) { for (NamedType subtype : st) { AnnotatedClass subtypeClass = AnnotatedClass.constructWithoutSuperTypes(subtype.getType(), ai, config); // One more thing: name may be either in reference, or in subtype: if (!subtype.hasName()) { subtype = new NamedType(subtype.getType(), ai.findTypeName(subtypeClass)); } _collectAndResolve(subtypeClass, subtype, config, ai, collectedSubtypes); } } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/TypeSerializerBase.java0000644000175000017500000000146111655120726033431 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.TypeSerializer; import org.codehaus.jackson.map.jsontype.TypeIdResolver; /** * @since 1.5 */ public abstract class TypeSerializerBase extends TypeSerializer { protected final TypeIdResolver _idResolver; protected final BeanProperty _property; protected TypeSerializerBase(TypeIdResolver idRes, BeanProperty property) { _idResolver = idRes; _property = property; } @Override public abstract JsonTypeInfo.As getTypeInclusion(); @Override public String getPropertyName() { return null; } @Override public TypeIdResolver getTypeIdResolver() { return _idResolver; } } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootjackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/MinimalClassNameIdResolver.javajackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/MinimalClassNameIdResolver.0000644000175000017500000000415511655120726034200 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.annotate.JsonTypeInfo; public class MinimalClassNameIdResolver extends ClassNameIdResolver { /** * Package name of the base class, to be used for determining common * prefix that can be omitted from included type id. * Does not include the trailing dot. */ protected final String _basePackageName; /** * Same as {@link #_basePackageName}, but includes trailing dot. */ protected final String _basePackagePrefix; protected MinimalClassNameIdResolver(JavaType baseType, TypeFactory typeFactory) { super(baseType, typeFactory); String base = baseType.getRawClass().getName(); int ix = base.lastIndexOf('.'); if (ix < 0) { // can this ever occur? _basePackageName = ""; _basePackagePrefix = "."; } else { _basePackagePrefix = base.substring(0, ix+1); _basePackageName = base.substring(0, ix); } } @Override public JsonTypeInfo.Id getMechanism() { return JsonTypeInfo.Id.MINIMAL_CLASS; } @Override public String idFromValue(Object value) { String n = value.getClass().getName(); if (n.startsWith(_basePackagePrefix)) { // note: we will leave the leading dot in there return n.substring(_basePackagePrefix.length()-1); } return n; } @Override public JavaType typeFromId(String id) { if (id.startsWith(".")) { StringBuilder sb = new StringBuilder(id.length() + _basePackageName.length()); if (_basePackageName.length() == 0) { // no package; must remove leading '.' from id sb.append(id.substring(1)); } else { // otherwise just concatenate package, with leading-dot-partial name sb.append(_basePackageName).append(id); } id = sb.toString(); } return super.typeFromId(id); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/TypeIdResolverBase.java0000644000175000017500000000137211655120726033377 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.type.JavaType; public abstract class TypeIdResolverBase implements TypeIdResolver { protected final TypeFactory _typeFactory; /** * Common base type for all polymorphic instances handled. */ protected final JavaType _baseType; protected TypeIdResolverBase(JavaType baseType, TypeFactory typeFactory) { _baseType = baseType; _typeFactory = typeFactory; } @Override public void init(JavaType bt) { /* Standard type id resolvers do not need this; * only useful for custom ones. */ } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/impl/AsArrayTypeSerializer.java0000644000175000017500000000636711655120726034133 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype.impl; import java.io.IOException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.jsontype.TypeIdResolver; /** * Type serializer that will embed type information in an array, * as the first element, and actual value as the second element. * * @since 1.5 * @author tatu */ public class AsArrayTypeSerializer extends TypeSerializerBase { public AsArrayTypeSerializer(TypeIdResolver idRes, BeanProperty property) { super(idRes, property); } @Override public As getTypeInclusion() { return As.WRAPPER_ARRAY; } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeStartArray(); jgen.writeString(_idResolver.idFromValue(value)); jgen.writeStartObject(); } @Override public void writeTypePrefixForObject(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { jgen.writeStartArray(); jgen.writeString(_idResolver.idFromValueAndType(value, type)); jgen.writeStartObject(); } @Override public void writeTypePrefixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeStartArray(); jgen.writeString(_idResolver.idFromValue(value)); jgen.writeStartArray(); } @Override public void writeTypePrefixForArray(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { jgen.writeStartArray(); jgen.writeString(_idResolver.idFromValueAndType(value, type)); jgen.writeStartArray(); } @Override public void writeTypePrefixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // only need the wrapper array jgen.writeStartArray(); jgen.writeString(_idResolver.idFromValue(value)); } @Override public void writeTypePrefixForScalar(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { // only need the wrapper array jgen.writeStartArray(); jgen.writeString(_idResolver.idFromValueAndType(value, type)); } @Override public void writeTypeSuffixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { jgen.writeEndObject(); jgen.writeEndArray(); } @Override public void writeTypeSuffixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // wrapper array first, and then array caller needs to close jgen.writeEndArray(); jgen.writeEndArray(); } @Override public void writeTypeSuffixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException { // just the wrapper array to close jgen.writeEndArray(); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/TypeIdResolver.java0000644000175000017500000000466411655120726031652 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.type.JavaType; /** * Interface that defines standard API for converting types * to type identifiers and vice versa. Used by type resolvers * ({@link org.codehaus.jackson.map.TypeSerializer}, * {@link org.codehaus.jackson.map.TypeDeserializer}) for converting * between type and matching id; id is stored in JSON and needed for * creating instances of proper subtypes when deserializing values. * * @since 1.5 */ public interface TypeIdResolver { /* /********************************************************** /* Initialization/configuration methods /********************************************************** */ /** * Method that will be called once before any type resolution calls; * used to initialize instance with configuration. This is necessary * since instances may be created via reflection, without ability to * call specific constructor to pass in configuration settings. * * @param baseType Base type for which this id resolver instance is * used */ public void init(JavaType baseType); /* /********************************************************** /* Conversions between types and type ids /********************************************************** */ /** * Method called to serialize type of the type of given value * as a String to include in serialized JSON content. */ public String idFromValue(Object value); /** * Alternative method used for determining type from combination of * value and type, using suggested type (that serializer provides) * and possibly value of that type. Most common implementation will * use suggested type as is. * * @since 1.8 */ public String idFromValueAndType(Object value, Class suggestedType); /** * Method called to resolve type from given type identifier. */ public JavaType typeFromId(String id); /* /********************************************************** /* Accessors for metadata /********************************************************** */ /** * Accessor for mechanism that this resolver uses for determining * type id from type. Mostly informational; not required to be called * or used. */ public JsonTypeInfo.Id getMechanism(); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/SubtypeResolver.java0000644000175000017500000000250011655120726032072 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype; import java.util.Collection; import org.codehaus.jackson.map.AnnotationIntrospector; import org.codehaus.jackson.map.MapperConfig; import org.codehaus.jackson.map.introspect.AnnotatedClass; import org.codehaus.jackson.map.introspect.AnnotatedMember; /** * Helper object used for handling registration on resolving of supertypes * to subtypes. * * @since 1.5 */ public abstract class SubtypeResolver { /** * Method for registering specified subtypes (possibly including type * names); for type entries without name, non-qualified class name * as used as name (unless overridden by annotation). */ public abstract void registerSubtypes(NamedType... types); public abstract void registerSubtypes(Class... classes); /** * Method for finding out all reachable subtypes for a property specified * by given element (method or field) */ public abstract Collection collectAndResolveSubtypes(AnnotatedMember property, MapperConfig config, AnnotationIntrospector ai); /** * Method for finding out all reachable subtypes for given type. */ public abstract Collection collectAndResolveSubtypes(AnnotatedClass basetype, MapperConfig config, AnnotationIntrospector ai); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/package-info.java0000644000175000017500000000061311655120726031244 0ustar jamespagejamespage/** * Package that contains interfaces that define how to implement * functionality for dynamically resolving type during deserialization. * This is needed for complete handling of polymorphic types, where * actual type can not be determined statically (declared type is * a supertype of actual polymorphic serialized types). * * @since 1.5 */ package org.codehaus.jackson.map.jsontype; jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/jsontype/TypeResolverBuilder.java0000644000175000017500000001267511655120726032705 0ustar jamespagejamespagepackage org.codehaus.jackson.map.jsontype; import java.util.Collection; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.annotate.JsonTypeInfo.As; import org.codehaus.jackson.map.BeanProperty; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.TypeDeserializer; import org.codehaus.jackson.map.TypeSerializer; import org.codehaus.jackson.type.JavaType; /** * Interface that defines builders that are configured based on * annotations (like {@link JsonTypeInfo} or JAXB annotations), * and produce type serializers and deserializers used for * handling type information embedded in JSON to allow for safe * polymorphic type handling. *

* Builder is first initialized by calling {@link #init} method, and then * configured using setXxx (and registerXxx) * methods. Finally, after calling all configuration methods, * {@link #buildTypeSerializer} or {@link #buildTypeDeserializer} * will be called to get actual type resolver constructed * and used for resolving types for configured base type and its * subtypes. *

* Note that instances are used for two related but distinct use cases: *

    *
  • To create builders to use with explicit type information * inclusion (usually via @JsonTypeInfo annotation) *
  • *
  • To create builders when "default typing" is used; if so, type information * is automatically included for certain kind of types, regardless of annotations *
  • *
* Important distinction between the cases is that in first case, calls to * create builders are only made when builders are certainly needed; whereas * in second case builder has to first verify whether type information is * applicable for given type, and if not, just return null to indicate this. * * @since 1.5 * @author tatu */ public interface TypeResolverBuilder> { /* /********************************************************** /* Accessors /********************************************************** */ /** * Accessor for currently configured default type; implementation * class that may be used in case no valid type information is * available during type resolution * * @since 1.9 */ public Class getDefaultImpl(); /* /********************************************************** /* Actual builder methods /********************************************************** */ /** * Method for building type serializer based on current configuration * of this builder. * * @param baseType Base type that constructed resolver will * handle; super type of all types it will be used for. */ public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes, BeanProperty property); /** * Method for building type deserializer based on current configuration * of this builder. * * @param baseType Base type that constructed resolver will * handle; super type of all types it will be used for. * @param subtypes Known subtypes of the base type. */ public TypeDeserializer buildTypeDeserializer( DeserializationConfig config, JavaType baseType, Collection subtypes, BeanProperty property); /* /********************************************************** /* Initialization method(s) that must be called before other /* configuration /********************************************************** */ /** * Initialization method that is called right after constructing * the builder instance. * * @param idType Which type metadata is used * @param res (optional) Custom type id resolver used, if any * * @return Resulting builder instance (usually this builder, * but not necessarily) */ public T init(JsonTypeInfo.Id idType, TypeIdResolver res); /* /********************************************************** /* Methods for configuring resolver to build /********************************************************** */ /** * Method for specifying mechanism to use for including type metadata * in JSON. * If not explicitly called, setting defaults to * {@link As#PROPERTY}. * * @param includeAs Mechanism used for including type metadata in JSON * * @return Resulting builder instance (usually this builder, * but not necessarily) */ public T inclusion(As includeAs); /** * Method for specifying name of property used for including type * information. Not used for all inclusion mechanisms; * usually only used with {@link As#PROPERTY}. *

* If not explicitly called, name of property to use is based on * defaults for {@link org.codehaus.jackson.annotate.JsonTypeInfo.Id} configured. * * @param propName Name of JSON property to use for including * type information * * @return Resulting builder instance (usually this builder, * but not necessarily) */ public T typeProperty(String propName); /** * Method for specifying default implementation to use if type id * is either not available, or can not be resolved. * * @since 1.9 */ public T defaultImpl(Class defaultImpl); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/KeyDeserializers.java0000644000175000017500000000154411655120726030327 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.type.JavaType; /** * Interface that defines API for simple extensions that can provide additional deserializers * for deserializer Map keys of various types, from JSON property names. * Access is by a single callback method; instance is to either return * a configured {@link KeyDeserializer} for specified type, or null to indicate that it * does not support handling of the type. In latter case, further calls can be made * for other providers; in former case returned key deserializer is used for handling of * key instances of specified type. * * @since 1.8 */ public interface KeyDeserializers { public KeyDeserializer findKeyDeserializer(JavaType type, DeserializationConfig config, BeanDescription beanDesc, BeanProperty property) throws JsonMappingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/BeanPropertyDefinition.java0000644000175000017500000000423211655120726031471 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.map.introspect.AnnotatedField; import org.codehaus.jackson.map.introspect.AnnotatedMember; import org.codehaus.jackson.map.introspect.AnnotatedMethod; import org.codehaus.jackson.map.introspect.AnnotatedParameter; import org.codehaus.jackson.map.util.Named; /** * Simple value classes that contain definitions of properties, * used during introspection of properties to use for * serialization and deserialization purposes. * These instances are created before actual {@link BeanProperty} * instances are created, i.e. they are used earlier in the process * flow. * * @since 1.9 */ public abstract class BeanPropertyDefinition implements Named { /** * Accessor for name used for external representation (in JSON). */ @Override // from Named public abstract String getName(); /** * Accessor that can be used to determine implicit name from underlying * element(s) before possible renaming. This is the "internal" * name derived from accessor ("x" from "getX"), and is not based on * annotations or naming strategy. */ public abstract String getInternalName(); public abstract boolean hasGetter(); public abstract boolean hasSetter(); public abstract boolean hasField(); public abstract boolean hasConstructorParameter(); public boolean couldDeserialize() { return getMutator() != null; } public boolean couldSerialize() { return getAccessor() != null; } public abstract AnnotatedMethod getGetter(); public abstract AnnotatedMethod getSetter(); public abstract AnnotatedField getField(); public abstract AnnotatedParameter getConstructorParameter(); /** * Method used to find accessor (getter, field to access) to use for accessing * value of the property. * Null if no such member exists. */ public abstract AnnotatedMember getAccessor(); /** * Method used to find mutator (constructor parameter, setter, field) to use for * changing value of the property. * Null if no such member exists. */ public abstract AnnotatedMember getMutator(); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/JsonSerializable.java0000644000175000017500000000224011655120726030303 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import org.codehaus.jackson.*; /** * Interface that can be implemented by objects that know how to * serialize themselves to JSON, using {@link JsonGenerator} * (and {@link SerializerProvider} if necessary). *

* Note that implementing this interface binds implementing object * closely to Jackson API, and that it is often not necessary to do * so -- if class is a bean, it can be serialized without * implementing this interface. *

* NOTE: as of version 1.5, this interface is missing one crucial * aspect, that of dealing with type information embedding. * Because of this, this interface is deprecated, although will be * fully supported for all 1.x releases, and will work except for * cases where polymorphic type information handling is needed for * type (in which case implementing if {@link JsonSerializableWithType} is crucial). * * @see org.codehaus.jackson.map.JsonSerializableWithType * * @since 1.5 */ @Deprecated public interface JsonSerializable { public void serialize(JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ObjectMapper.java0000644000175000017500000031314411655120726027426 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.*; import java.lang.reflect.Type; import java.net.URL; import java.text.DateFormat; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import org.codehaus.jackson.*; import org.codehaus.jackson.annotate.JsonAutoDetect; import org.codehaus.jackson.annotate.JsonMethod; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.io.SegmentedStringWriter; import org.codehaus.jackson.io.SerializedString; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.deser.*; import org.codehaus.jackson.map.introspect.BasicClassIntrospector; import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector; import org.codehaus.jackson.map.introspect.VisibilityChecker; import org.codehaus.jackson.map.ser.*; import org.codehaus.jackson.map.jsontype.NamedType; import org.codehaus.jackson.map.jsontype.SubtypeResolver; import org.codehaus.jackson.map.jsontype.TypeResolverBuilder; import org.codehaus.jackson.map.jsontype.impl.StdSubtypeResolver; import org.codehaus.jackson.map.jsontype.impl.StdTypeResolverBuilder; import org.codehaus.jackson.map.type.SimpleType; import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.map.type.TypeModifier; import org.codehaus.jackson.node.*; import org.codehaus.jackson.schema.JsonSchema; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.TypeReference; import org.codehaus.jackson.util.*; /** * This mapper (or, data binder, or codec) provides functionality for * converting between Java objects (instances of JDK provided core classes, * beans), and matching JSON constructs. * It will use instances of {@link JsonParser} and {@link JsonGenerator} * for implementing actual reading/writing of JSON. *

* The main conversion API is defined in {@link ObjectCodec}, so that * implementation details of this class need not be exposed to * streaming parser and generator classes. *

* Note on caching: root-level deserializers are always cached, and accessed * using full (generics-aware) type information. This is different from * caching of referenced types, which is more limited and is done only * for a subset of all deserializer types. The main reason for difference * is that at root-level there is no incoming reference (and hence no * referencing property, no referral information or annotations to * produce differing deserializers), and that the performance impact * greatest at root level (since it'll essentially cache the full * graph of deserializers involved). */ public class ObjectMapper extends ObjectCodec implements Versioned { /* /********************************************************** /* Helper classes, enums /********************************************************** */ /** * Enumeration used with {@link ObjectMapper#enableDefaultTyping()} * to specify what kind of types (classes) default typing should * be used for. It will only be used if no explicit type information * is found, but this enumeration further limits subset of those * types. * * @since 1.5 */ public enum DefaultTyping { /** * This value means that only properties that have * {@link java.lang.Object} as declared type (including * generic types without explicit type) will use default * typing. */ JAVA_LANG_OBJECT, /** * Value that means that default typing will be used for * properties with declared type of {@link java.lang.Object} * or an abstract type (abstract class or interface). * Note that this does not include array types. */ OBJECT_AND_NON_CONCRETE, /** * Value that means that default typing will be used for * all types covered by {@link #OBJECT_AND_NON_CONCRETE} * plus all array types for them. */ NON_CONCRETE_AND_ARRAYS, /** * Value that means that default typing will be used for * all non-final types, with exception of small number of * "natural" types (String, Boolean, Integer, Double), which * can be correctly inferred from JSON; as well as for * all arrays of non-final types. */ NON_FINAL } /** * Customized {@link TypeResolverBuilder} that provides type resolver builders * used with so-called "default typing" * (see {@link ObjectMapper#enableDefaultTyping()} for details). *

* Type resolver construction is based on configuration: implementation takes care * of only providing builders in cases where type information should be applied. * This is important since build calls may be sent for any and all types, and * type information should NOT be applied to all of them. */ public static class DefaultTypeResolverBuilder extends StdTypeResolverBuilder { /** * Definition of what types is this default typer valid for. */ protected final DefaultTyping _appliesFor; public DefaultTypeResolverBuilder(DefaultTyping t) { _appliesFor = t; } @Override public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection subtypes, BeanProperty property) { return useForType(baseType) ? super.buildTypeDeserializer(config, baseType, subtypes, property) : null; } @Override public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes, BeanProperty property) { return useForType(baseType) ? super.buildTypeSerializer(config, baseType, subtypes, property) : null; } /** * Method called to check if the default type handler should be * used for given type. * Note: "natural types" (String, Boolean, Integer, Double) will never * use typing; that is both due to them being concrete and final, * and since actual serializers and deserializers will also ignore any * attempts to enforce typing. */ public boolean useForType(JavaType t) { switch (_appliesFor) { case NON_CONCRETE_AND_ARRAYS: if (t.isArrayType()) { t = t.getContentType(); } // fall through case OBJECT_AND_NON_CONCRETE: return (t.getRawClass() == Object.class) || !t.isConcrete(); case NON_FINAL: if (t.isArrayType()) { t = t.getContentType(); } return !t.isFinal(); // includes Object.class default: //case JAVA_LANG_OBJECT: return (t.getRawClass() == Object.class); } } } /* /********************************************************** /* Internal constants, singletons /********************************************************** */ // Quick little shortcut, to avoid having to use global TypeFactory instance... private final static JavaType JSON_NODE_TYPE = SimpleType.constructUnsafe(JsonNode.class); /* !!! 03-Apr-2009, tatu: Should try to avoid direct reference... but not * sure what'd be simple and elegant way. So until then: */ protected final static ClassIntrospector DEFAULT_INTROSPECTOR = BasicClassIntrospector.instance; // 16-May-2009, tatu: Ditto ^^^ protected final static AnnotationIntrospector DEFAULT_ANNOTATION_INTROSPECTOR = new JacksonAnnotationIntrospector(); /** * @since 1.5 */ protected final static VisibilityChecker STD_VISIBILITY_CHECKER = VisibilityChecker.Std.defaultInstance(); /* /********************************************************** /* Configuration settings, shared /********************************************************** */ /** * Factory used to create {@link JsonParser} and {@link JsonGenerator} * instances as necessary. */ protected final JsonFactory _jsonFactory; /** * Registered concrete subtypes that can be used instead of (or * in addition to) ones declared using annotations. * * @since 1.6 */ protected SubtypeResolver _subtypeResolver; /** * Specific factory used for creating {@link JavaType} instances; * needed to allow modules to add more custom type handling * (mostly to support types of non-Java JVM languages) */ protected TypeFactory _typeFactory; /** * Provider for values to inject in deserialized POJOs. * * @since 1.9 */ protected InjectableValues _injectableValues; /* /********************************************************** /* Configuration settings, serialization /********************************************************** */ /** * Configuration object that defines basic global * settings for the serialization process */ protected SerializationConfig _serializationConfig; /** * Object that manages access to serializers used for serialization, * including caching. * It is configured with {@link #_serializerFactory} to allow * for constructing custom serializers. */ protected SerializerProvider _serializerProvider; /** * Serializer factory used for constructing serializers. */ protected SerializerFactory _serializerFactory; /* /********************************************************** /* Configuration settings, deserialization /********************************************************** */ /** * Configuration object that defines basic global * settings for the serialization process */ protected DeserializationConfig _deserializationConfig; /** * Object that manages access to deserializers used for deserializing * JSON content into Java objects, including possible caching * of the deserializers. It contains a reference to * {@link DeserializerFactory} to use for constructing acutal deserializers. */ protected DeserializerProvider _deserializerProvider; /* /********************************************************** /* Caching /********************************************************** */ /* Note: handling of serializers and deserializers is not symmetric; * and as a result, only root-level deserializers can be cached here. * This is mostly because typing and resolution for deserializers is * fully static; whereas it is quite dynamic for serialization. */ /** * We will use a separate main-level Map for keeping track * of root-level deserializers. This is where most succesful * cache lookups get resolved. * Map will contain resolvers for all kinds of types, including * container types: this is different from the component cache * which will only cache bean deserializers. *

* Given that we don't expect much concurrency for additions * (should very quickly converge to zero after startup), let's * explicitly define a low concurrency setting. *

* Since version 1.5, these may are either "raw" deserializers (when * no type information is needed for base type), or type-wrapped * deserializers (if it is needed) */ final protected ConcurrentHashMap> _rootDeserializers = new ConcurrentHashMap>(64, 0.6f, 2); /* /********************************************************** /* Life-cycle: constructing instance /********************************************************** */ /** * Default constructor, which will construct the default * {@link JsonFactory} as necessary, use * {@link StdSerializerProvider} as its * {@link SerializerProvider}, and * {@link BeanSerializerFactory} as its * {@link SerializerFactory}. * This means that it * can serialize all standard JDK types, as well as regular * Java Beans (based on method names and Jackson-specific annotations), * but does not support JAXB annotations. */ public ObjectMapper() { this(null, null, null); } /** * Construct mapper that uses specified {@link JsonFactory} * for constructing necessary {@link JsonParser}s and/or * {@link JsonGenerator}s. */ public ObjectMapper(JsonFactory jf) { this(jf, null, null); } /** * Construct mapper that uses specified {@link SerializerFactory} * for constructing necessary serializers. * * @deprecated Use other constructors instead; note that * you can just set serializer factory with {@link #setSerializerFactory} */ @Deprecated public ObjectMapper(SerializerFactory sf) { this(null, null, null); setSerializerFactory(sf); } public ObjectMapper(JsonFactory jf, SerializerProvider sp, DeserializerProvider dp) { this(jf, sp, dp, null, null); } /** * * @param jf JsonFactory to use: if null, a new {@link MappingJsonFactory} will be constructed * @param sp SerializerProvider to use: if null, a {@link StdSerializerProvider} will be constructed * @param dp DeserializerProvider to use: if null, a {@link StdDeserializerProvider} will be constructed * @param sconfig Serialization configuration to use; if null, basic {@link SerializationConfig} * will be constructed * @param dconfig Deserialization configuration to use; if null, basic {@link DeserializationConfig} * will be constructed */ public ObjectMapper(JsonFactory jf, SerializerProvider sp, DeserializerProvider dp, SerializationConfig sconfig, DeserializationConfig dconfig) { /* 02-Mar-2009, tatu: Important: we MUST default to using * the mapping factory, otherwise tree serialization will * have problems with POJONodes. * 03-Jan-2010, tatu: and obviously we also must pass 'this', * to create actual linking. */ _jsonFactory = (jf == null) ? new MappingJsonFactory(this) : jf; // and default type factory is shared one _typeFactory = TypeFactory.defaultInstance(); _serializationConfig = (sconfig != null) ? sconfig : new SerializationConfig(DEFAULT_INTROSPECTOR, DEFAULT_ANNOTATION_INTROSPECTOR, STD_VISIBILITY_CHECKER, null, null, _typeFactory, null); _deserializationConfig = (dconfig != null) ? dconfig : new DeserializationConfig(DEFAULT_INTROSPECTOR, DEFAULT_ANNOTATION_INTROSPECTOR, STD_VISIBILITY_CHECKER, null, null, _typeFactory, null); _serializerProvider = (sp == null) ? new StdSerializerProvider() : sp; _deserializerProvider = (dp == null) ? new StdDeserializerProvider() : dp; // Default serializer factory is stateless, can just assign _serializerFactory = BeanSerializerFactory.instance; } /* /********************************************************** /* Versioned impl /********************************************************** */ /** * Method that will return version information stored in and read from jar * that contains this class. * * @since 1.6 */ @Override public Version version() { return VersionUtil.versionFor(getClass()); } /* /********************************************************** /* Module registration /********************************************************** */ /** * Method for registering a module that can extend functionality * provided by this mapper; for example, by adding providers for * custom serializers and deserializers. * * @param module Module to register * * @since 1.7 */ public void registerModule(Module module) { /* Let's ensure we have access to name and version information, * even if we do not have immediate use for either. This way we know * that they will be available from beginning */ String name = module.getModuleName(); if (name == null) { throw new IllegalArgumentException("Module without defined name"); } Version version = module.version(); if (version == null) { throw new IllegalArgumentException("Module without defined version"); } final ObjectMapper mapper = this; // And then call registration module.setupModule(new Module.SetupContext() { // // // Accessors @Override public Version getMapperVersion() { return version(); } @Override public DeserializationConfig getDeserializationConfig() { return mapper.getDeserializationConfig(); } @Override public SerializationConfig getSerializationConfig() { return mapper.getSerializationConfig(); } @Override public boolean isEnabled(DeserializationConfig.Feature f) { return mapper.isEnabled(f); } @Override public boolean isEnabled(SerializationConfig.Feature f) { return mapper.isEnabled(f); } @Override public boolean isEnabled(JsonParser.Feature f) { return mapper.isEnabled(f); } @Override public boolean isEnabled(JsonGenerator.Feature f) { return mapper.isEnabled(f); } // // // Methods for registering handlers: deserializers, serializers @Override public void addDeserializers(Deserializers d) { mapper._deserializerProvider = mapper._deserializerProvider.withAdditionalDeserializers(d); } @Override public void addKeyDeserializers(KeyDeserializers d) { mapper._deserializerProvider = mapper._deserializerProvider.withAdditionalKeyDeserializers(d); } @Override public void addSerializers(Serializers s) { mapper._serializerFactory = mapper._serializerFactory.withAdditionalSerializers(s); } @Override public void addKeySerializers(Serializers s) { mapper._serializerFactory = mapper._serializerFactory.withAdditionalKeySerializers(s); } @Override public void addBeanSerializerModifier(BeanSerializerModifier modifier) { mapper._serializerFactory = mapper._serializerFactory.withSerializerModifier(modifier); } @Override public void addBeanDeserializerModifier(BeanDeserializerModifier modifier) { mapper._deserializerProvider = mapper._deserializerProvider.withDeserializerModifier(modifier); } // // // Methods for registering handlers: other @Override public void addAbstractTypeResolver(AbstractTypeResolver resolver) { mapper._deserializerProvider = mapper._deserializerProvider.withAbstractTypeResolver(resolver); } @Override public void addTypeModifier(TypeModifier modifier) { TypeFactory f = mapper._typeFactory; f = f.withModifier(modifier); mapper.setTypeFactory(f); } @Override public void addValueInstantiators(ValueInstantiators instantiators) { mapper._deserializerProvider = mapper._deserializerProvider.withValueInstantiators(instantiators); } @Override public void insertAnnotationIntrospector(AnnotationIntrospector ai) { mapper._deserializationConfig = mapper._deserializationConfig.withInsertedAnnotationIntrospector(ai); mapper._serializationConfig = mapper._serializationConfig.withInsertedAnnotationIntrospector(ai); } @Override public void appendAnnotationIntrospector(AnnotationIntrospector ai) { mapper._deserializationConfig = mapper._deserializationConfig.withAppendedAnnotationIntrospector(ai); mapper._serializationConfig = mapper._serializationConfig.withAppendedAnnotationIntrospector(ai); } @Override public void setMixInAnnotations(Class target, Class mixinSource) { mapper._deserializationConfig.addMixInAnnotations(target, mixinSource); mapper._serializationConfig.addMixInAnnotations(target, mixinSource); } }); } /** * Fluent-style alternative to {@link #registerModule}; functionally equivalent to: *

     *  mapper.registerModule(module);
     *  return mapper;
     *
* NOTE: name is unfortunately misleading in suggesting that a new instance * might be created (as is the case with most other 'withXxx()' methods * for Jackson core objects) -- this is not the case; rather, this is just * a variant of {@link #registerModule} but one that returns 'this' * (like it should return, but does not for historical reasons). * * @since 1.8 */ public ObjectMapper withModule(Module module) { registerModule(module); return this; } /* /********************************************************** /* Configuration: main config object access /********************************************************** */ /** * Method that returns the shared default {@link SerializationConfig} * object that defines configuration settings for serialization. * Returned object is "live" meaning that changes will be used * for future serialization operations for this mapper when using * mapper's default configuration */ public SerializationConfig getSerializationConfig() { return _serializationConfig; } /** * Method that creates a copy of * the shared default {@link SerializationConfig} object * that defines configuration settings for serialization. * Since it is a copy, any changes made to the configuration * object will NOT directly affect serialization done using * basic serialization methods that use the shared object (that is, * ones that do not take separate {@link SerializationConfig} * argument. *

* The use case is that of changing object settings of the configuration * (like date format being used, see {@link SerializationConfig#setDateFormat}). */ public SerializationConfig copySerializationConfig() { return _serializationConfig.createUnshared(_subtypeResolver); } /** * Method for replacing the shared default serialization configuration * object. */ public ObjectMapper setSerializationConfig(SerializationConfig cfg) { _serializationConfig = cfg; return this; } /** * Method that returns * the shared default {@link DeserializationConfig} object * that defines configuration settings for deserialization. * Returned object is "live" meaning that changes will be used * for future deserialization operations for this mapper when using * mapper's default configuration */ public DeserializationConfig getDeserializationConfig() { return _deserializationConfig; } /** * Method that creates a copy of * the shared default {@link DeserializationConfig} object * that defines configuration settings for deserialization. * Since it is a copy, any changes made to the configuration * object will NOT directly affect deserialization done using * basic deserialization methods that use the shared object (that is, * ones that do not take separate {@link DeserializationConfig} * argument. *

* The use case is that of changing object settings of the configuration * (like deserialization problem handler, * see {@link DeserializationConfig#addHandler}) */ public DeserializationConfig copyDeserializationConfig() { return _deserializationConfig.createUnshared(_subtypeResolver) .passSerializationFeatures(_serializationConfig._featureFlags); } /** * Method for replacing the shared default deserialization configuration * object. */ public ObjectMapper setDeserializationConfig(DeserializationConfig cfg) { _deserializationConfig = cfg; return this; } /* /********************************************************** /* Configuration: ser/deser factory, provider access /********************************************************** */ /** * Method for setting specific {@link SerializerFactory} to use * for constructing (bean) serializers. */ public ObjectMapper setSerializerFactory(SerializerFactory f) { _serializerFactory = f; return this; } /** * Method for setting specific {@link SerializerProvider} to use * for handling caching of {@link JsonSerializer} instances. */ public ObjectMapper setSerializerProvider(SerializerProvider p) { _serializerProvider = p; return this; } /** * @since 1.4 */ public SerializerProvider getSerializerProvider() { return _serializerProvider; } /** * Method for setting specific {@link DeserializerProvider} to use * for handling caching of {@link JsonDeserializer} instances. */ public ObjectMapper setDeserializerProvider(DeserializerProvider p) { _deserializerProvider = p; return this; } /** * @since 1.4 */ public DeserializerProvider getDeserializerProvider() { return _deserializerProvider; } /* /********************************************************** /* Configuration, introspection /********************************************************** */ /** * Method for accessing currently configured visibility checker; * object used for determining whether given property element * (method, field, constructor) can be auto-detected or not. * * @since 1.5 */ public VisibilityChecker getVisibilityChecker() { return _serializationConfig.getDefaultVisibilityChecker(); } /** * Method for setting currently configured visibility checker; * object used for determining whether given property element * (method, field, constructor) can be auto-detected or not. * This default checker is used if no per-class overrides * are defined. * * @since 1.5 */ public void setVisibilityChecker(VisibilityChecker vc) { _deserializationConfig = _deserializationConfig.withVisibilityChecker(vc); _serializationConfig = _serializationConfig.withVisibilityChecker(vc); } /** * Convenience method that allows changing configuration for * underlying {@link VisibilityChecker}s, to change details of what kinds of * properties are auto-detected. * Basically short cut for doing: *

     *  mapper.setVisibilityChecker(
     *     mapper.getVisibilityChecker().withVisibility(forMethod, visibility)
     *  );
     *
* one common use case would be to do: *
     *  mapper.setVisibility(JsonMethod.FIELD, Visibility.ANY);
     *
* which would make all member fields serializable without further annotations, * instead of just public fields (default setting). * * @param forMethod Type of property descriptor affected (field, getter/isGetter, * setter, creator) * @param visibility Minimum visibility to require for the property descriptors of type * * @return Modified mapper instance (that is, "this"), to allow chaining * of configuration calls * * @since 1.9 */ public ObjectMapper setVisibility(JsonMethod forMethod, JsonAutoDetect.Visibility visibility) { _deserializationConfig = _deserializationConfig.withVisibility(forMethod, visibility); _serializationConfig = _serializationConfig.withVisibility(forMethod, visibility); return this; } /** * Method for accessing subtype resolver in use. * * @since 1.6 */ public SubtypeResolver getSubtypeResolver() { if (_subtypeResolver == null) { _subtypeResolver = new StdSubtypeResolver(); } return _subtypeResolver; } /** * Method for setting custom subtype resolver to use. * * @since 1.6 */ public void setSubtypeResolver(SubtypeResolver r) { _subtypeResolver = r; } /** * Method for changing {@link AnnotationIntrospector} used by this * mapper instance for both serialization and deserialization * * @since 1.8 */ public ObjectMapper setAnnotationIntrospector(AnnotationIntrospector ai) { _serializationConfig = _serializationConfig.withAnnotationIntrospector(ai); _deserializationConfig = _deserializationConfig.withAnnotationIntrospector(ai); return this; } /** * Method for setting custom property naming strategy to use. * * @since 1.8 */ public ObjectMapper setPropertyNamingStrategy(PropertyNamingStrategy s) { _serializationConfig = _serializationConfig.withPropertyNamingStrategy(s); _deserializationConfig = _deserializationConfig.withPropertyNamingStrategy(s); return this; } /** * Method for setting defalt POJO property inclusion strategy for serialization. * Equivalent to: *
     *  mapper.setSerializationConfig(mapper.getSerializationConfig().withSerializationInclusion(incl));
     *
* * @since 1.9 */ public ObjectMapper setSerializationInclusion(JsonSerialize.Inclusion incl) { _serializationConfig = _serializationConfig.withSerializationInclusion(incl); return this; } /* /********************************************************** /* Type information configuration (1.5+) /********************************************************** */ /** * Convenience method that is equivalent to calling *
     *  enableObjectTyping(DefaultTyping.OBJECT_AND_NON_CONCRETE);
     *
*/ public ObjectMapper enableDefaultTyping() { return enableDefaultTyping(DefaultTyping.OBJECT_AND_NON_CONCRETE); } /** * Convenience method that is equivalent to calling *
     *  enableObjectTyping(dti, JsonTypeInfo.As.WRAPPER_ARRAY);
     *
*/ public ObjectMapper enableDefaultTyping(DefaultTyping dti) { return enableDefaultTyping(dti, JsonTypeInfo.As.WRAPPER_ARRAY); } /** * Method for enabling automatic inclusion of type information, needed * for proper deserialization of polymorphic types (unless types * have been annotated with {@link org.codehaus.jackson.annotate.JsonTypeInfo}). * * @param applicability Defines kinds of types for which additional type information * is added; see {@link DefaultTyping} for more information. */ public ObjectMapper enableDefaultTyping(DefaultTyping applicability, JsonTypeInfo.As includeAs) { TypeResolverBuilder typer = new DefaultTypeResolverBuilder(applicability); // we'll always use full class name, when using defaulting typer = typer.init(JsonTypeInfo.Id.CLASS, null); typer = typer.inclusion(includeAs); return setDefaultTyping(typer); } /** * Method for enabling automatic inclusion of type information -- needed * for proper deserialization of polymorphic types (unless types * have been annotated with {@link org.codehaus.jackson.annotate.JsonTypeInfo}) -- * using "As.PROPERTY" inclusion mechanism and specified property name * to use for inclusion (default being "@class" since default type information * always uses class name as type identifier) * * @since 1.7 */ public ObjectMapper enableDefaultTypingAsProperty(DefaultTyping applicability, String propertyName) { TypeResolverBuilder typer = new DefaultTypeResolverBuilder(applicability); // we'll always use full class name, when using defaulting typer = typer.init(JsonTypeInfo.Id.CLASS, null); typer = typer.inclusion(JsonTypeInfo.As.PROPERTY); typer = typer.typeProperty(propertyName); return setDefaultTyping(typer); } /** * Method for disabling automatic inclusion of type information; if so, only * explicitly annotated types (ones with * {@link org.codehaus.jackson.annotate.JsonTypeInfo}) will have * additional embedded type information. */ public ObjectMapper disableDefaultTyping() { return setDefaultTyping(null); } /** * Method for enabling automatic inclusion of type information, using * specified handler object for determining which types this affects, * as well as details of how information is embedded. * * @param typer Type information inclusion handler * * */ public ObjectMapper setDefaultTyping(TypeResolverBuilder typer) { _deserializationConfig = _deserializationConfig.withTypeResolverBuilder(typer); _serializationConfig = _serializationConfig.withTypeResolverBuilder(typer); return this; } /** * Method for registering specified class as a subtype, so that * typename-based resolution can link supertypes to subtypes * (as an alternative to using annotations). * Type for given class is determined from appropriate annotation; * or if missing, default name (unqualified class name) * * @since 1.6 */ public void registerSubtypes(Class... classes) { getSubtypeResolver().registerSubtypes(classes); } /** * Method for registering specified class as a subtype, so that * typename-based resolution can link supertypes to subtypes * (as an alternative to using annotations). * Name may be provided as part of argument, but if not will * be based on annotations or use default name (unqualified * class name). * * @since 1.6 */ public void registerSubtypes(NamedType... types) { getSubtypeResolver().registerSubtypes(types); } /* /********************************************************** /* Configuration, basic type handling /********************************************************** */ /** * Accessor for getting currently configured {@link TypeFactory} instance. * * @since 1.8 */ public TypeFactory getTypeFactory() { return _typeFactory; } /** * Method that can be used to override {@link TypeFactory} instance * used by this mapper. *

* Note: will also set {@link TypeFactory} that deserialization and * serialization config objects use. */ public ObjectMapper setTypeFactory(TypeFactory f) { _typeFactory = f; _deserializationConfig = _deserializationConfig.withTypeFactory(f); _serializationConfig = _serializationConfig.withTypeFactory(f); return this; } /** * Convenience method for constructing {@link JavaType} out of given * type (typically java.lang.Class), but without explicit * context. * * @since 1.8 */ public JavaType constructType(Type t) { return _typeFactory.constructType(t); } /* /********************************************************** /* Configuration, deserialization /********************************************************** */ /** * Method for specifying {@link JsonNodeFactory} to use for * constructing root level tree nodes (via method * {@link #createObjectNode} * * @since 1.2 */ public ObjectMapper setNodeFactory(JsonNodeFactory f) { _deserializationConfig = _deserializationConfig.withNodeFactory(f); return this; } /* /********************************************************** /* Configuration, serialization /********************************************************** */ /** * Convenience method that is equivalent to: *

     *  mapper.setFilters(mapper.getSerializationConfig().withFilters(filterProvider));
     *
*

* Note that usually it is better to use method {@link #filteredWriter}; however, sometimes * this method is more convenient. For example, some frameworks only allow configuring * of ObjectMapper instances and not ObjectWriters. * * @since 1.8 */ public void setFilters(FilterProvider filterProvider) { _serializationConfig = _serializationConfig.withFilters(filterProvider); } /* /********************************************************** /* Configuration, other /********************************************************** */ /** * Method that can be used to get hold of {@link JsonFactory} that this * mapper uses if it needs to construct {@link JsonParser}s * and/or {@link JsonGenerator}s. * * @return {@link JsonFactory} that this mapper uses when it needs to * construct Json parser and generators */ public JsonFactory getJsonFactory() { return _jsonFactory; } /** * Method for configuring the default {@link DateFormat} to use when serializing time * values as Strings, and deserializing from JSON Strings. * This is preferably to directly modifying {@link SerializationConfig} and * {@link DeserializationConfig} instances. * If you need per-request configuration, use {@link #writer(DateFormat)} to * create properly configured {@link ObjectWriter} and use that; this because * {@link ObjectWriter}s are thread-safe whereas ObjectMapper itself is only * thread-safe when configuring methods (such as this one) are NOT called. * * @since 1.8 */ public void setDateFormat(DateFormat dateFormat) { _deserializationConfig = _deserializationConfig.withDateFormat(dateFormat); _serializationConfig = _serializationConfig.withDateFormat(dateFormat); } /** * Method for configuring {@link HandlerInstantiator} to use for creating * instances of handlers (such as serializers, deserializers, type and type * id resolvers), given a class. * * @param hi Instantiator to use; if null, use the default implementation */ public void setHandlerInstantiator(HandlerInstantiator hi) { _deserializationConfig = _deserializationConfig.withHandlerInstantiator(hi); _serializationConfig = _serializationConfig.withHandlerInstantiator(hi); } /** * @since 1.9 */ public ObjectMapper setInjectableValues(InjectableValues injectableValues) { _injectableValues = injectableValues; return this; } /* /********************************************************** /* Configuration, simple features /********************************************************** */ /** * Method for changing state of an on/off serialization feature for * this object mapper. *

* This is method is basically a shortcut method for calling * {@link SerializationConfig#set} on the shared {@link SerializationConfig} * object with given arguments. */ @SuppressWarnings("deprecation") public ObjectMapper configure(SerializationConfig.Feature f, boolean state) { _serializationConfig.set(f, state); return this; } /** * Method for changing state of an on/off deserialization feature for * this object mapper. *

* This is method is basically a shortcut method for calling * {@link DeserializationConfig#set} on the shared {@link DeserializationConfig} * object with given arguments. */ @SuppressWarnings("deprecation") public ObjectMapper configure(DeserializationConfig.Feature f, boolean state) { _deserializationConfig.set(f, state); return this; } /** * Method for changing state of an on/off {@link JsonParser} feature for * {@link JsonFactory} instance this object mapper uses. *

* This is method is basically a shortcut method for calling * {@link JsonFactory#setParserFeature} on the shared * {@link JsonFactory} this mapper uses (which is accessible * using {@link #getJsonFactory}). * * @since 1.2 */ public ObjectMapper configure(JsonParser.Feature f, boolean state) { _jsonFactory.configure(f, state); return this; } /** * Method for changing state of an on/off {@link JsonGenerator} feature for * {@link JsonFactory} instance this object mapper uses. *

* This is method is basically a shortcut method for calling * {@link JsonFactory#setGeneratorFeature} on the shared * {@link JsonFactory} this mapper uses (which is accessible * using {@link #getJsonFactory}). * * @since 1.2 */ public ObjectMapper configure(JsonGenerator.Feature f, boolean state) { _jsonFactory.configure(f, state); return this; } /** * Method for enabling specified {@link DeserializationConfig} features. * Modifies and returns this instance; no new object is created. * * @since 1.9 */ public ObjectMapper enable(DeserializationConfig.Feature... f) { _deserializationConfig = _deserializationConfig.with(f); return this; } /** * Method for enabling specified {@link DeserializationConfig} features. * Modifies and returns this instance; no new object is created. * * @since 1.9 */ public ObjectMapper disable(DeserializationConfig.Feature... f) { _deserializationConfig = _deserializationConfig.without(f); return this; } /** * Method for enabling specified {@link DeserializationConfig} features. * Modifies and returns this instance; no new object is created. * * @since 1.9 */ public ObjectMapper enable(SerializationConfig.Feature... f) { _serializationConfig = _serializationConfig.with(f); return this; } /** * Method for enabling specified {@link DeserializationConfig} features. * Modifies and returns this instance; no new object is created. * * @since 1.9 */ public ObjectMapper disable(SerializationConfig.Feature... f) { _serializationConfig = _serializationConfig.without(f); return this; } /** * Convenience method, equivalent to: *

     *  getSerializationConfig().isEnabled(f);
     *
* * @since 1.9 */ public boolean isEnabled(SerializationConfig.Feature f) { return _serializationConfig.isEnabled(f); } /** * Convenience method, equivalent to: *
     *  getDeserializationConfig().isEnabled(f);
     *
* * @since 1.9 */ public boolean isEnabled(DeserializationConfig.Feature f) { return _deserializationConfig.isEnabled(f); } /** * Convenience method, equivalent to: *
     *  getJsonFactory().isEnabled(f);
     *
* * @since 1.9 */ public boolean isEnabled(JsonParser.Feature f) { return _jsonFactory.isEnabled(f); } /** * Convenience method, equivalent to: *
     *  getJsonFactory().isEnabled(f);
     *
* * @since 1.9 */ public boolean isEnabled(JsonGenerator.Feature f) { return _jsonFactory.isEnabled(f); } /** * Method that can be used to get hold of {@link JsonNodeFactory} * that this mapper will use when directly constructing * root {@link JsonNode} instances for Trees. *

* Note: this is just a shortcut for calling *

     *   getDeserializationConfig().getNodeFactory()
     *
* * @since 1.2 */ public JsonNodeFactory getNodeFactory() { return _deserializationConfig.getNodeFactory(); } /* /********************************************************** /* Public API (from ObjectCodec): deserialization /* (mapping from JSON to Java types); /* main methods /********************************************************** */ /** * Method to deserialize JSON content into a non-container * type (it can be an array type, however): typically a bean, array * or a wrapper type (like {@link java.lang.Boolean}). *

* Note: this method should NOT be used if the result type is a * container ({@link java.util.Collection} or {@link java.util.Map}. * The reason is that due to type erasure, key and value types * can not be introspected when using this method. */ @Override @SuppressWarnings("unchecked") public T readValue(JsonParser jp, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readValue(copyDeserializationConfig(), jp, _typeFactory.constructType(valueType)); } /** * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using so-called * "super type token" (see ) * and specifically needs to be used if the root type is a * parameterized (generic) container type. */ @Override @SuppressWarnings("unchecked") public T readValue(JsonParser jp, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readValue(copyDeserializationConfig(), jp, _typeFactory.constructType(valueTypeRef)); } /** * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using * Jackson specific type; instance of which can be constructed using * {@link TypeFactory}. */ @Override @SuppressWarnings("unchecked") public T readValue(JsonParser jp, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readValue(copyDeserializationConfig(), jp, valueType); } /** * Method to deserialize JSON content as tree expressed * using set of {@link JsonNode} instances. Returns * root of the resulting tree (where root can consist * of just a single node if the current event is a * value event, not container). */ @Override public JsonNode readTree(JsonParser jp) throws IOException, JsonProcessingException { /* 02-Mar-2009, tatu: One twist; deserialization provider * will map JSON null straight into Java null. But what * we want to return is the "null node" instead. */ /* 05-Aug-2011, tatu: Also, must check for EOF here before * calling readValue(), since that'll choke on it otherwise */ DeserializationConfig cfg = copyDeserializationConfig(); JsonToken t = jp.getCurrentToken(); if (t == null) { t = jp.nextToken(); if (t == null) { return null; } } JsonNode n = (JsonNode) _readValue(cfg, jp, JSON_NODE_TYPE); return (n == null) ? getNodeFactory().nullNode() : n; } /** * Method for reading sequence of Objects from parser stream. *

* Note that {@link ObjectReader} has more complete set of variants. * * @since 1.8 */ @Override public MappingIterator readValues(JsonParser jp, JavaType valueType) throws IOException, JsonProcessingException { DeserializationConfig config = copyDeserializationConfig(); DeserializationContext ctxt = _createDeserializationContext(jp, config); JsonDeserializer deser = _findRootDeserializer(config, valueType); return new MappingIterator(valueType, jp, ctxt, deser); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ @Override public MappingIterator readValues(JsonParser jp, Class valueType) throws IOException, JsonProcessingException { return readValues(jp, _typeFactory.constructType(valueType)); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ @Override public MappingIterator readValues(JsonParser jp, TypeReference valueTypeRef) throws IOException, JsonProcessingException { return readValues(jp, _typeFactory.constructType(valueTypeRef)); } /* /********************************************************** /* Public API not included in ObjectCodec: deserialization /* (mapping from JSON to Java types) /********************************************************** */ /** * Method to deserialize JSON content into a non-container * type (it can be an array type, however): typically a bean, array * or a wrapper type (like {@link java.lang.Boolean}). *

* Note: this method should NOT be used if the result type is a * container ({@link java.util.Collection} or {@link java.util.Map}. * The reason is that due to type erasure, key and value types * can not be introspected when using this method. * @since 1.1 * * @param cfg Specific deserialization configuration to use for * this operation. Note that not all config settings can * be changed on per-operation basis: some changeds only take effect * before calling the operation for the first time (for the mapper * instance) */ @SuppressWarnings("unchecked") public T readValue(JsonParser jp, Class valueType, DeserializationConfig cfg) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readValue(cfg, jp, _typeFactory.constructType(valueType)); } /** * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using so-called * "super type token" (see ) * and specifically needs to be used if the root type is a * parameterized (generic) container type. * * @param cfg Specific deserialization configuration to use for * this operation. Note that not all config settings can * be changed on per-operation basis: some changeds only take effect * before calling the operation for the first time (for the mapper * instance) * * @since 1.1 */ @SuppressWarnings("unchecked") public T readValue(JsonParser jp, TypeReference valueTypeRef, DeserializationConfig cfg) throws IOException, JsonParseException, JsonMappingException { return (T) _readValue(cfg, jp, _typeFactory.constructType(valueTypeRef)); } /** * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using * Jackson specific type; instance of which can be constructed using * {@link TypeFactory}. * * @param cfg Specific deserialization configuration to use for * this operation. Note that not all config settings can * be changed on per-operation basis: some changeds only take effect * before calling the operation for the first time (for the mapper * instance) * * @since 1.1 */ @SuppressWarnings("unchecked") public T readValue(JsonParser jp, JavaType valueType, DeserializationConfig cfg) throws IOException, JsonParseException, JsonMappingException { return (T) _readValue(cfg, jp, valueType); } /** * Method to deserialize JSON content as tree expressed * using set of {@link JsonNode} instances. Returns * root of the resulting tree (where root can consist * of just a single node if the current event is a * value event, not container). * * @param cfg Specific deserialization configuration to use for * this operation. Note that not all config settings can * be changed on per-operation basis: some changeds only take effect * before calling the operation for the first time (for the mapper * instance) * * @since 1.1 */ public JsonNode readTree(JsonParser jp, DeserializationConfig cfg) throws IOException, JsonProcessingException { JsonNode n = (JsonNode) _readValue(cfg, jp, JSON_NODE_TYPE); return (n == null) ? NullNode.instance : n; } /** * Method to deserialize JSON content as tree expressed * using set of {@link JsonNode} instances. * Returns root of the resulting tree (where root can consist * of just a single node if the current event is a * value event, not container). * * @param in Input stream used to read JSON content * for building the JSON tree. * * @since 1.3 */ public JsonNode readTree(InputStream in) throws IOException, JsonProcessingException { JsonNode n = (JsonNode) _readMapAndClose(_jsonFactory.createJsonParser(in), JSON_NODE_TYPE); return (n == null) ? NullNode.instance : n; } /** * Method to deserialize JSON content as tree expressed * using set of {@link JsonNode} instances. * Returns root of the resulting tree (where root can consist * of just a single node if the current event is a * value event, not container). * * @param r Reader used to read JSON content * for building the JSON tree. * * @since 1.3 */ public JsonNode readTree(Reader r) throws IOException, JsonProcessingException { JsonNode n = (JsonNode) _readMapAndClose(_jsonFactory.createJsonParser(r), JSON_NODE_TYPE); return (n == null) ? NullNode.instance : n; } /** * Method to deserialize JSON content as tree expressed using set of {@link JsonNode} instances. * Returns root of the resulting tree (where root can consist of just a single node if the current * event is a value event, not container). * * @param content JSON content to parse to build the JSON tree. * * @since 1.3 */ public JsonNode readTree(String content) throws IOException, JsonProcessingException { JsonNode n = (JsonNode) _readMapAndClose(_jsonFactory.createJsonParser(content), JSON_NODE_TYPE); return (n == null) ? NullNode.instance : n; } /** * Method to deserialize JSON content as tree expressed using set of {@link JsonNode} instances. * Returns root of the resulting tree (where root can consist of just a single node if the current * event is a value event, not container). * * @param content JSON content to parse to build the JSON tree. * * @since 1.9 */ public JsonNode readTree(byte[] content) throws IOException, JsonProcessingException { JsonNode n = (JsonNode) _readMapAndClose(_jsonFactory.createJsonParser(content), JSON_NODE_TYPE); return (n == null) ? NullNode.instance : n; } /** * Method to deserialize JSON content as tree expressed using set of {@link JsonNode} instances. * Returns root of the resulting tree (where root can consist of just a single node if the current * event is a value event, not container). * * @param file File of which contents to parse as JSON for building a tree instance * * @since 1.9 */ public JsonNode readTree(File file) throws IOException, JsonProcessingException { JsonNode n = (JsonNode) _readMapAndClose(_jsonFactory.createJsonParser(file), JSON_NODE_TYPE); return (n == null) ? NullNode.instance : n; } /** * Method to deserialize JSON content as tree expressed using set of {@link JsonNode} instances. * Returns root of the resulting tree (where root can consist of just a single node if the current * event is a value event, not container). * * @param source URL to use for fetching contents to parse as JSON for building a tree instance * * @since 1.9 */ public JsonNode readTree(URL source) throws IOException, JsonProcessingException { JsonNode n = (JsonNode) _readMapAndClose(_jsonFactory.createJsonParser(source), JSON_NODE_TYPE); return (n == null) ? NullNode.instance : n; } /* /********************************************************** /* Public API (from ObjectCodec): serialization /* (mapping from Java types to Json) /********************************************************** */ /** * Method that can be used to serialize any Java value as * JSON output, using provided {@link JsonGenerator}. */ @Override public void writeValue(JsonGenerator jgen, Object value) throws IOException, JsonGenerationException, JsonMappingException { SerializationConfig config = copySerializationConfig(); if (config.isEnabled(SerializationConfig.Feature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) { _writeCloseableValue(jgen, value, config); } else { _serializerProvider.serializeValue(config, jgen, value, _serializerFactory); if (config.isEnabled(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE)) { jgen.flush(); } } } /** * Method that can be used to serialize any Java value as * JSON output, using provided {@link JsonGenerator}, * configured as per passed configuration object. * * @since 1.1 */ public void writeValue(JsonGenerator jgen, Object value, SerializationConfig config) throws IOException, JsonGenerationException, JsonMappingException { // [JACKSON-282] Consider java.util.Closeable if (config.isEnabled(SerializationConfig.Feature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) { _writeCloseableValue(jgen, value, config); } else { _serializerProvider.serializeValue(config, jgen, value, _serializerFactory); if (config.isEnabled(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE)) { jgen.flush(); } } } /** * Method to serialize given JSON Tree, using generator * provided. */ @Override public void writeTree(JsonGenerator jgen, JsonNode rootNode) throws IOException, JsonProcessingException { SerializationConfig config = copySerializationConfig(); _serializerProvider.serializeValue(config, jgen, rootNode, _serializerFactory); if (config.isEnabled(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE)) { jgen.flush(); } } /** * Method to serialize given Json Tree, using generator * provided. * * @since 1.1 */ public void writeTree(JsonGenerator jgen, JsonNode rootNode, SerializationConfig cfg) throws IOException, JsonProcessingException { _serializerProvider.serializeValue(cfg, jgen, rootNode, _serializerFactory); if (cfg.isEnabled(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE)) { jgen.flush(); } } /* /********************************************************** /* Public API (from ObjectCodec): Tree Model support /********************************************************** */ /** *

* Note: return type is co-variant, as basic ObjectCodec * abstraction can not refer to concrete node types (as it's * part of core package, whereas impls are part of mapper * package) * * @since 1.2 */ @Override public ObjectNode createObjectNode() { return _deserializationConfig.getNodeFactory().objectNode(); } /** *

* Note: return type is co-variant, as basic ObjectCodec * abstraction can not refer to concrete node types (as it's * part of core package, whereas impls are part of mapper * package) * * @since 1.2 */ @Override public ArrayNode createArrayNode() { return _deserializationConfig.getNodeFactory().arrayNode(); } /** * Method for constructing a {@link JsonParser} out of JSON tree * representation. * * @param n Root node of the tree that resulting parser will read from * * @since 1.3 */ @Override public JsonParser treeAsTokens(JsonNode n) { return new TreeTraversingParser(n, this); } /** * Convenience conversion method that will bind data given JSON tree * contains into specific value (usually bean) type. *

* Equivalent to: *

     *   objectMapper.convertValue(n, valueClass);
     *
*/ @Override public T treeToValue(JsonNode n, Class valueType) throws IOException, JsonParseException, JsonMappingException { return readValue(treeAsTokens(n), valueType); } /** * Reverse of {@link #treeToValue}; given a value (usually bean), will * construct equivalent JSON Tree representation. Functionally same * as if serializing value into JSON and parsing JSON as tree, but * more efficient. * * @param Actual node type; usually either basic {@link JsonNode} or * {@link org.codehaus.jackson.node.ObjectNode} * @param fromValue Bean value to convert * @return Root node of the resulting JSON tree * * @since 1.6 */ @SuppressWarnings("unchecked") public T valueToTree(Object fromValue) throws IllegalArgumentException { if (fromValue == null) return null; TokenBuffer buf = new TokenBuffer(this); JsonNode result; try { writeValue(buf, fromValue); JsonParser jp = buf.asParser(); result = readTree(jp); jp.close(); } catch (IOException e) { // should not occur, no real i/o... throw new IllegalArgumentException(e.getMessage(), e); } return (T) result; } /* /********************************************************** /* Extended Public API, accessors /********************************************************** */ /** * Method that can be called to check whether mapper thinks * it could serialize an instance of given Class. * Check is done * by checking whether a serializer can be found for the type. * * @return True if mapper can find a serializer for instances of * given class (potentially serializable), false otherwise (not * serializable) */ public boolean canSerialize(Class type) { return _serializerProvider.hasSerializerFor(copySerializationConfig(), type, _serializerFactory); } /** * Method that can be called to check whether mapper thinks * it could deserialize an Object of given type. * Check is done * by checking whether a deserializer can be found for the type. * * @return True if mapper can find a serializer for instances of * given class (potentially serializable), false otherwise (not * serializable) */ public boolean canDeserialize(JavaType type) { return _deserializerProvider.hasValueDeserializerFor(copyDeserializationConfig(), type); } /* /********************************************************** /* Extended Public API, deserialization, /* convenience methods /********************************************************** */ @SuppressWarnings("unchecked") public T readValue(File src, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueType)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(File src, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueTypeRef)); } @SuppressWarnings("unchecked") public T readValue(File src, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), valueType); } @SuppressWarnings("unchecked") public T readValue(URL src, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueType)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(URL src, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueTypeRef)); } @SuppressWarnings("unchecked") public T readValue(URL src, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), valueType); } @SuppressWarnings("unchecked") public T readValue(String content, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readMapAndClose(_jsonFactory.createJsonParser(content), _typeFactory.constructType(valueType)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(String content, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(content), _typeFactory.constructType(valueTypeRef)); } @SuppressWarnings("unchecked") public T readValue(String content, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(content), valueType); } @SuppressWarnings("unchecked") public T readValue(Reader src, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueType)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(Reader src, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueTypeRef)); } @SuppressWarnings("unchecked") public T readValue(Reader src, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), valueType); } @SuppressWarnings("unchecked") public T readValue(InputStream src, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueType)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(InputStream src, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueTypeRef)); } @SuppressWarnings("unchecked") public T readValue(InputStream src, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), valueType); } /** * @since 1.8 */ @SuppressWarnings("unchecked") public T readValue(byte[] src, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueType)); } @SuppressWarnings("unchecked") public T readValue(byte[] src, int offset, int len, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readMapAndClose(_jsonFactory.createJsonParser(src, offset, len), _typeFactory.constructType(valueType)); } /** * @since 1.8 */ @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(byte[] src, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), _typeFactory.constructType(valueTypeRef)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(byte[] src, int offset, int len, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src, offset, len), _typeFactory.constructType(valueTypeRef)); } /** * @since 1.8 */ @SuppressWarnings("unchecked") public T readValue(byte[] src, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src), valueType); } @SuppressWarnings("unchecked") public T readValue(byte[] src, int offset, int len, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readMapAndClose(_jsonFactory.createJsonParser(src, offset, len), valueType); } /** * Convenience method for converting results from given JSON tree into given * value type. Basically short-cut for: *
     *   mapper.readValue(mapper.treeAsTokens(root), valueType);
     *
* * @since 1.6 */ @SuppressWarnings("unchecked") public T readValue(JsonNode root, Class valueType) throws IOException, JsonParseException, JsonMappingException { // !!! TODO // _setupClassLoaderForDeserialization(valueType); return (T) _readValue(copyDeserializationConfig(), treeAsTokens(root), _typeFactory.constructType(valueType)); } /** * Convenience method for converting results from given JSON tree into given * value type. Basically short-cut for: *
     *   mapper.readValue(mapper.treeAsTokens(root), valueType);
     *
* * @since 1.6 */ @SuppressWarnings({ "unchecked", "rawtypes" }) public T readValue(JsonNode root, TypeReference valueTypeRef) throws IOException, JsonParseException, JsonMappingException { return (T) _readValue(copyDeserializationConfig(), treeAsTokens(root), _typeFactory.constructType(valueTypeRef)); } /** * Convenience method for converting results from given JSON tree into given * value type. Basically short-cut for: *
     *   mapper.readValue(mapper.treeAsTokens(root), valueType);
     *
* * @since 1.6 */ @SuppressWarnings("unchecked") public T readValue(JsonNode root, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { return (T) _readValue(copyDeserializationConfig(), treeAsTokens(root), valueType); } /* /********************************************************** /* Extended Public API: serialization /* (mapping from Java types to Json) /********************************************************** */ /** * Method that can be used to serialize any Java value as * JSON output, written to File provided. */ public void writeValue(File resultFile, Object value) throws IOException, JsonGenerationException, JsonMappingException { _configAndWriteValue(_jsonFactory.createJsonGenerator(resultFile, JsonEncoding.UTF8), value); } /** * Method that can be used to serialize any Java value as * JSON output, using output stream provided (using encoding * {@link JsonEncoding#UTF8}). *

* Note: method does not close the underlying stream explicitly * here; however, {@link JsonFactory} this mapper uses may choose * to close the stream depending on its settings (by default, * it will try to close it when {@link JsonGenerator} we construct * is closed). */ public void writeValue(OutputStream out, Object value) throws IOException, JsonGenerationException, JsonMappingException { _configAndWriteValue(_jsonFactory.createJsonGenerator(out, JsonEncoding.UTF8), value); } /** * Method that can be used to serialize any Java value as * JSON output, using Writer provided. *

* Note: method does not close the underlying stream explicitly * here; however, {@link JsonFactory} this mapper uses may choose * to close the stream depending on its settings (by default, * it will try to close it when {@link JsonGenerator} we construct * is closed). */ public void writeValue(Writer w, Object value) throws IOException, JsonGenerationException, JsonMappingException { _configAndWriteValue(_jsonFactory.createJsonGenerator(w), value); } /** * Method that can be used to serialize any Java value as * a String. Functionally equivalent to calling * {@link #writeValue(Writer,Object)} with {@link java.io.StringWriter} * and constructing String, but more efficient. * * @since 1.3 */ public String writeValueAsString(Object value) throws IOException, JsonGenerationException, JsonMappingException { // alas, we have to pull the recycler directly here... SegmentedStringWriter sw = new SegmentedStringWriter(_jsonFactory._getBufferRecycler()); _configAndWriteValue(_jsonFactory.createJsonGenerator(sw), value); return sw.getAndClear(); } /** * Method that can be used to serialize any Java value as * a byte array. Functionally equivalent to calling * {@link #writeValue(Writer,Object)} with {@link java.io.ByteArrayOutputStream} * and getting bytes, but more efficient. * Encoding used will be UTF-8. * * @since 1.5 */ public byte[] writeValueAsBytes(Object value) throws IOException, JsonGenerationException, JsonMappingException { ByteArrayBuilder bb = new ByteArrayBuilder(_jsonFactory._getBufferRecycler()); _configAndWriteValue(_jsonFactory.createJsonGenerator(bb, JsonEncoding.UTF8), value); byte[] result = bb.toByteArray(); bb.release(); return result; } /* /********************************************************** /* Extended Public API: constructing ObjectWriters /* for more advanced configuration /********************************************************** */ /** * Convenience method for constructing {@link ObjectWriter} * with default settings. * * @since 1.6 */ public ObjectWriter writer() { return new ObjectWriter(this, copySerializationConfig()); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using specified {@link DateFormat}; or, if * null passed, using timestamp (64-bit number. * * @since 1.9 */ public ObjectWriter writer(DateFormat df) { return new ObjectWriter(this, copySerializationConfig().withDateFormat(df)); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using specified JSON View (filter). * * @since 1.9 */ public ObjectWriter writerWithView(Class serializationView) { return new ObjectWriter(this, copySerializationConfig().withView(serializationView)); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using specified root type, instead of actual * runtime type of value. Type must be a super-type of runtime * type. * * @since 1.9 */ public ObjectWriter writerWithType(Class rootType) { JavaType t = (rootType == null) ? null : _typeFactory.constructType(rootType); return new ObjectWriter(this, copySerializationConfig(), t, /*PrettyPrinter*/null); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using specified root type, instead of actual * runtime type of value. Type must be a super-type of runtime type. * * @since 1.9 */ public ObjectWriter writerWithType(JavaType rootType) { return new ObjectWriter(this, copySerializationConfig(), rootType, /*PrettyPrinter*/null); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using specified root type, instead of actual * runtime type of value. Type must be a super-type of runtime type. * * @since 1.9 */ public ObjectWriter writerWithType(TypeReference rootType) { JavaType t = (rootType == null) ? null : _typeFactory.constructType(rootType); return new ObjectWriter(this, copySerializationConfig(), t, /*PrettyPrinter*/null); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using specified pretty printer for indentation * (or if null, no pretty printer) * * @since 1.9 */ public ObjectWriter writer(PrettyPrinter pp) { if (pp == null) { // need to use a marker to indicate explicit disabling of pp pp = ObjectWriter.NULL_PRETTY_PRINTER; } return new ObjectWriter(this, copySerializationConfig(), /*root type*/ null, pp); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using the default pretty printer for indentation * * @since 1.9 */ public ObjectWriter writerWithDefaultPrettyPrinter() { return new ObjectWriter(this, copySerializationConfig(), /*root type*/ null, _defaultPrettyPrinter()); } /** * Factory method for constructing {@link ObjectWriter} that will * serialize objects using specified filter provider. * * @since 1.9 */ public ObjectWriter writer(FilterProvider filterProvider) { return new ObjectWriter(this, copySerializationConfig().withFilters(filterProvider)); } /** * Factory method for constructing {@link ObjectWriter} that will * pass specific schema object to {@link JsonGenerator} used for * writing content. * * @param schema Schema to pass to generator * * @since 1.9 */ public ObjectWriter writer(FormatSchema schema) { return new ObjectWriter(this, copySerializationConfig(), schema); } /* /********************************************************** /* Deprecated ObjectWriter creator methods /********************************************************** */ /** * @deprecated Since 1.9, use {@link #writerWithType(Class)} instead. */ @Deprecated public ObjectWriter typedWriter(Class rootType) { return writerWithType(rootType); } /** * @deprecated Since 1.9, use {@link #writerWithType(JavaType)} instead. */ @Deprecated public ObjectWriter typedWriter(JavaType rootType) { return writerWithType(rootType); } /** * @deprecated Since 1.9, use {@link #writerWithType(TypeReference)} instead. */ @Deprecated public ObjectWriter typedWriter(TypeReference rootType) { return writerWithType(rootType); } /** * @deprecated Since 1.9, use {@link #writerWithView(Class)} instead. */ @Deprecated public ObjectWriter viewWriter(Class serializationView) { return writerWithView(serializationView); } /** * @deprecated Since 1.9, use {@link #writer(FilterProvider)} instead. */ @Deprecated public ObjectWriter prettyPrintingWriter(PrettyPrinter pp) { return writer(pp); } /** * @deprecated Since 1.9, use {@link #writerWithDefaultPrettyPrinter} instead. */ @Deprecated public ObjectWriter defaultPrettyPrintingWriter() { return writerWithDefaultPrettyPrinter(); } /** * @deprecated Since 1.9, use {@link #writer(FilterProvider)} instead. */ @Deprecated public ObjectWriter filteredWriter(FilterProvider filterProvider) { return writer(filterProvider); } /** * @deprecated Since 1.9, use {@link #writer(FilterProvider)} instead. */ @Deprecated public ObjectWriter schemaBasedWriter(FormatSchema schema) { return writer(schema); } /* /********************************************************** /* Extended Public API: constructing ObjectReaders /* for more advanced configuration /********************************************************** */ /** * Factory method for constructing {@link ObjectReader} with * default settings. Note that the resulting instance is NOT usable as is, * without defining expected value type. * * @since 1.6 */ public ObjectReader reader() { return new ObjectReader(this, copyDeserializationConfig()) .withInjectableValues(_injectableValues); } /** * Factory method for constructing {@link ObjectReader} that will * update given Object (usually Bean, but can be a Collection or Map * as well, but NOT an array) with JSON data. Deserialization occurs * normally except that the root-level value in JSON is not used for * instantiating a new object; instead give updateable object is used * as root. * Runtime type of value object is used for locating deserializer, * unless overridden by other factory methods of {@link ObjectReader} * * @since 1.9 */ public ObjectReader readerForUpdating(Object valueToUpdate) { JavaType t = _typeFactory.constructType(valueToUpdate.getClass()); return new ObjectReader(this, copyDeserializationConfig(), t, valueToUpdate, null, _injectableValues); } /** * Factory method for constructing {@link ObjectReader} that will * read or update instances of specified type * * @since 1.6 */ public ObjectReader reader(JavaType type) { return new ObjectReader(this, copyDeserializationConfig(), type, null, null, _injectableValues); } /** * Factory method for constructing {@link ObjectReader} that will * read or update instances of specified type * * @since 1.6 */ public ObjectReader reader(Class type) { return reader(_typeFactory.constructType(type)); } /** * Factory method for constructing {@link ObjectReader} that will * read or update instances of specified type * * @since 1.6 */ public ObjectReader reader(TypeReference type) { return reader(_typeFactory.constructType(type)); } /** * Factory method for constructing {@link ObjectReader} that will * use specified {@link JsonNodeFactory} for constructing JSON trees. * * @since 1.6 */ public ObjectReader reader(JsonNodeFactory f) { return new ObjectReader(this, copyDeserializationConfig()).withNodeFactory(f); } /** * Factory method for constructing {@link ObjectReader} that will * pass specific schema object to {@link JsonParser} used for * reading content. * * @param schema Schema to pass to parser * * @since 1.8 */ public ObjectReader reader(FormatSchema schema) { return new ObjectReader(this, copyDeserializationConfig(), null, null, schema, _injectableValues); } /** * Factory method for constructing {@link ObjectReader} that will * use specified injectable values. * * @param injectableValues Injectable values to use * * @since 1.9 */ public ObjectReader reader(InjectableValues injectableValues) { return new ObjectReader(this, copyDeserializationConfig(), null, null, null, injectableValues); } /* /********************************************************** /* Deprecated ObjectReader creator methods /********************************************************** */ /** * @deprecated Since 1.9, use {@link #readerForUpdating} instead. */ @Deprecated public ObjectReader updatingReader(Object valueToUpdate) { return readerForUpdating(valueToUpdate); } /** * @deprecated Since 1.9, use {@link #reader(FormatSchema)} instead. */ @Deprecated public ObjectReader schemaBasedReader(FormatSchema schema) { return reader(schema); } /* /********************************************************** /* Extended Public API: convenience type conversion /********************************************************** */ /** * Convenience method for doing two-step conversion from given value, into * instance of given value type. This is functionality equivalent to first * serializing given value into JSON, then binding JSON data into value * of given type, but may be executed without fully serializing into * JSON. Same converters (serializers, deserializers) will be used as for * data binding, meaning same object mapper configuration works. * * @throws IllegalArgumentException If conversion fails due to incompatible type; * if so, root cause will contain underlying checked exception data binding * functionality threw */ @SuppressWarnings("unchecked") public T convertValue(Object fromValue, Class toValueType) throws IllegalArgumentException { return (T) _convert(fromValue, _typeFactory.constructType(toValueType)); } @SuppressWarnings({ "unchecked", "rawtypes" }) public T convertValue(Object fromValue, TypeReference toValueTypeRef) throws IllegalArgumentException { return (T) _convert(fromValue, _typeFactory.constructType(toValueTypeRef)); } @SuppressWarnings("unchecked") public T convertValue(Object fromValue, JavaType toValueType) throws IllegalArgumentException { return (T) _convert(fromValue, toValueType); } protected Object _convert(Object fromValue, JavaType toValueType) throws IllegalArgumentException { // sanity check for null first: if (fromValue == null) return null; /* Then use TokenBuffer, which is a JsonGenerator: * (see [JACKSON-175]) */ TokenBuffer buf = new TokenBuffer(this); try { writeValue(buf, fromValue); // and provide as with a JsonParser for contents as well! JsonParser jp = buf.asParser(); Object result = readValue(jp, toValueType); jp.close(); return result; } catch (IOException e) { // should not occur, no real i/o... throw new IllegalArgumentException(e.getMessage(), e); } } /* /********************************************************** /* Extended Public API: JSON Schema generation /********************************************************** */ /** * Generate Json-schema * instance for specified class. * * @param t The class to generate schema for * @return Constructed JSON schema. */ public JsonSchema generateJsonSchema(Class t) throws JsonMappingException { return generateJsonSchema(t, copySerializationConfig()); } /** * Generate Json-schema * instance for specified class, using specific * serialization configuration * * @param t The class to generate schema for * @return Constructed JSON schema. */ public JsonSchema generateJsonSchema(Class t, SerializationConfig cfg) throws JsonMappingException { return _serializerProvider.generateJsonSchema(t, cfg, _serializerFactory); } /* /********************************************************** /* Internal methods for serialization, overridable /********************************************************** */ /** * Helper method that should return default pretty-printer to * use for generators constructed by this mapper, when instructed * to use default pretty printer. * * @since 1.7 */ protected PrettyPrinter _defaultPrettyPrinter() { return new DefaultPrettyPrinter(); } /** * Method called to configure the generator as necessary and then * call write functionality */ protected final void _configAndWriteValue(JsonGenerator jgen, Object value) throws IOException, JsonGenerationException, JsonMappingException { SerializationConfig cfg = copySerializationConfig(); // [JACKSON-96]: allow enabling pretty printing for ObjectMapper directly if (cfg.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) { jgen.useDefaultPrettyPrinter(); } // [JACKSON-282]: consider Closeable if (cfg.isEnabled(SerializationConfig.Feature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) { _configAndWriteCloseable(jgen, value, cfg); return; } boolean closed = false; try { _serializerProvider.serializeValue(cfg, jgen, value, _serializerFactory); closed = true; jgen.close(); } finally { /* won't try to close twice; also, must catch exception (so it * will not mask exception that is pending) */ if (!closed) { try { jgen.close(); } catch (IOException ioe) { } } } } protected final void _configAndWriteValue(JsonGenerator jgen, Object value, Class viewClass) throws IOException, JsonGenerationException, JsonMappingException { SerializationConfig cfg = copySerializationConfig().withView(viewClass); if (cfg.isEnabled(SerializationConfig.Feature.INDENT_OUTPUT)) { jgen.useDefaultPrettyPrinter(); } // [JACKSON-282]: consider Closeable if (cfg.isEnabled(SerializationConfig.Feature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) { _configAndWriteCloseable(jgen, value, cfg); return; } boolean closed = false; try { _serializerProvider.serializeValue(cfg, jgen, value, _serializerFactory); closed = true; jgen.close(); } finally { if (!closed) { try { jgen.close(); } catch (IOException ioe) { } } } } /** * Helper method used when value to serialize is {@link Closeable} and its close() * method is to be called right after serialization has been called */ private final void _configAndWriteCloseable(JsonGenerator jgen, Object value, SerializationConfig cfg) throws IOException, JsonGenerationException, JsonMappingException { Closeable toClose = (Closeable) value; try { _serializerProvider.serializeValue(cfg, jgen, value, _serializerFactory); JsonGenerator tmpJgen = jgen; jgen = null; tmpJgen.close(); Closeable tmpToClose = toClose; toClose = null; tmpToClose.close(); } finally { /* Need to close both generator and value, as long as they haven't yet * been closed */ if (jgen != null) { try { jgen.close(); } catch (IOException ioe) { } } if (toClose != null) { try { toClose.close(); } catch (IOException ioe) { } } } } /** * Helper method used when value to serialize is {@link Closeable} and its close() * method is to be called right after serialization has been called */ private final void _writeCloseableValue(JsonGenerator jgen, Object value, SerializationConfig cfg) throws IOException, JsonGenerationException, JsonMappingException { Closeable toClose = (Closeable) value; try { _serializerProvider.serializeValue(cfg, jgen, value, _serializerFactory); if (cfg.isEnabled(SerializationConfig.Feature.FLUSH_AFTER_WRITE_VALUE)) { jgen.flush(); } Closeable tmpToClose = toClose; toClose = null; tmpToClose.close(); } finally { if (toClose != null) { try { toClose.close(); } catch (IOException ioe) { } } } } /* /********************************************************** /* Internal methods for deserialization, overridable /********************************************************** */ /** * Actual implementation of value reading+binding operation. */ protected Object _readValue(DeserializationConfig cfg, JsonParser jp, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { /* First: may need to read the next token, to initialize * state (either before first read from parser, or after * previous token has been cleared) */ Object result; JsonToken t = _initForReading(jp); if (t == JsonToken.VALUE_NULL) { // [JACKSON-643]: Ask JsonDeserializer what 'null value' to use: result = _findRootDeserializer(cfg, valueType).getNullValue(); } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { result = null; } else { // pointing to event other than null DeserializationContext ctxt = _createDeserializationContext(jp, cfg); JsonDeserializer deser = _findRootDeserializer(cfg, valueType); // ok, let's get the value if (cfg.isEnabled(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE)) { result = _unwrapAndDeserialize(jp, valueType, ctxt, deser); } else { result = deser.deserialize(jp, ctxt); } } // Need to consume the token too jp.clearCurrentToken(); return result; } protected Object _readMapAndClose(JsonParser jp, JavaType valueType) throws IOException, JsonParseException, JsonMappingException { try { Object result; JsonToken t = _initForReading(jp); if (t == JsonToken.VALUE_NULL) { // [JACKSON-643]: Ask JsonDeserializer what 'null value' to use: // (note: probably no need to make a copy of config for just this access) result = _findRootDeserializer(this._deserializationConfig, valueType).getNullValue(); } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { result = null; } else { DeserializationConfig cfg = copyDeserializationConfig(); DeserializationContext ctxt = _createDeserializationContext(jp, cfg); JsonDeserializer deser = _findRootDeserializer(cfg, valueType); if (cfg.isEnabled(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE)) { result = _unwrapAndDeserialize(jp, valueType, ctxt, deser); } else { result = deser.deserialize(jp, ctxt); } } // Need to consume the token too jp.clearCurrentToken(); return result; } finally { try { jp.close(); } catch (IOException ioe) { } } } /** * Method called to ensure that given parser is ready for reading * content for data binding. * * @return First token to be used for data binding after this call: * can never be null as exception will be thrown if parser can not * provide more tokens. * * @throws IOException if the underlying input source has problems during * parsing * @throws JsonParseException if parser has problems parsing content * @throws JsonMappingException if the parser does not have any more * content to map (note: Json "null" value is considered content; * enf-of-stream not) */ protected JsonToken _initForReading(JsonParser jp) throws IOException, JsonParseException, JsonMappingException { /* First: must point to a token; if not pointing to one, advance. * This occurs before first read from JsonParser, as well as * after clearing of current token. */ JsonToken t = jp.getCurrentToken(); if (t == null) { // and then we must get something... t = jp.nextToken(); if (t == null) { /* [JACKSON-99] Should throw EOFException, closest thing * semantically */ throw new EOFException("No content to map to Object due to end of input"); } } return t; } protected Object _unwrapAndDeserialize(JsonParser jp, JavaType rootType, DeserializationContext ctxt, JsonDeserializer deser) throws IOException, JsonParseException, JsonMappingException { SerializedString rootName = _deserializerProvider.findExpectedRootName(ctxt.getConfig(), rootType); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw JsonMappingException.from(jp, "Current token not START_OBJECT (needed to unwrap root name '" +rootName+"'), but "+jp.getCurrentToken()); } if (jp.nextToken() != JsonToken.FIELD_NAME) { throw JsonMappingException.from(jp, "Current token not FIELD_NAME (to contain expected root name '" +rootName+"'), but "+jp.getCurrentToken()); } String actualName = jp.getCurrentName(); if (!rootName.getValue().equals(actualName)) { throw JsonMappingException.from(jp, "Root name '"+actualName+"' does not match expected ('"+rootName +"') for type "+rootType); } // ok, then move to value itself.... jp.nextToken(); Object result = deser.deserialize(jp, ctxt); // and last, verify that we now get matching END_OBJECT if (jp.nextToken() != JsonToken.END_OBJECT) { throw JsonMappingException.from(jp, "Current token not END_OBJECT (to match wrapper object with root name '" +rootName+"'), but "+jp.getCurrentToken()); } return result; } /* /********************************************************** /* Internal methods, other /********************************************************** */ /** * Method called to locate deserializer for the passed root-level value. */ protected JsonDeserializer _findRootDeserializer(DeserializationConfig cfg, JavaType valueType) throws JsonMappingException { // First: have we already seen it? JsonDeserializer deser = _rootDeserializers.get(valueType); if (deser != null) { return deser; } // Nope: need to ask provider to resolve it deser = _deserializerProvider.findTypedValueDeserializer(cfg, valueType, null); if (deser == null) { // can this happen? throw new JsonMappingException("Can not find a deserializer for type "+valueType); } _rootDeserializers.put(valueType, deser); return deser; } protected DeserializationContext _createDeserializationContext(JsonParser jp, DeserializationConfig cfg) { return new StdDeserializationContext(cfg, jp, _deserializerProvider, _injectableValues); } //Allows use of the correct classloader (primarily for OSGi), separating framework from application //should be safe to use in all contexts /* protected void _setupClassLoaderForDeserialization(Class valueType) { ClassLoader loader = (valueType.getClassLoader() == null) ? Thread.currentThread().getContextClassLoader() : valueType.getClassLoader(); Thread.currentThread().setContextClassLoader(loader); } */ } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/package-info.java0000644000175000017500000000240411655120726027371 0ustar jamespagejamespage/** Contains basic mapper (conversion) functionality that allows for converting between regular streaming json content and Java objects (beans or Tree Model: support for both is via {@link org.codehaus.jackson.map.ObjectMapper} class, as well as convenience methods included in {@link org.codehaus.jackson.JsonParser}

Object mapper will convert Json content to ant from basic Java wrapper types (Integer, Boolean, Double), Collection types (List, Map), Java Beans, Strings and nulls.

Tree mapper builds dynamically typed tree of JsonNodes from Json content (and writes such trees as Json), similar to how DOM model works with xml. Main benefits over Object mapping are:

  • No null checks are needed (dummy nodes are created as necessary to represent "missing" Object fields and Array elements)
  • No type casts are usually needed: all public access methods are defined in basic JsonNode class, and when "incompatible" method (such as Array element access on, say, Boolean node) is used, returned node is virtual "missing" node.
Because of its dynamic nature, Tree mapping is often convenient for basic path access and tree navigation, where structure of the resulting tree is known in advance. */ package org.codehaus.jackson.map; jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/TypeSerializer.java0000644000175000017500000001375711655120726030035 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.annotate.JsonTypeInfo; import org.codehaus.jackson.map.jsontype.TypeIdResolver; /** * Interface for serializing type information regarding instances of specified * base type (super class), so that exact subtype can be properly deserialized * later on. These instances are to be called by regular * {@link org.codehaus.jackson.map.JsonSerializer}s using proper contextual * calls, to add type information using mechanism type serializer was * configured with. * * @since 1.5 * @author tatus */ public abstract class TypeSerializer { /* /********************************************************** /* Introspection /********************************************************** */ /** * Accessor for type information inclusion method * that serializer uses; indicates how type information * is embedded in resulting JSON. */ public abstract JsonTypeInfo.As getTypeInclusion(); /** * Name of property that contains type information, if * property-based inclusion is used. */ public abstract String getPropertyName(); /** * Accessor for object that handles conversions between * types and matching type ids. */ public abstract TypeIdResolver getTypeIdResolver(); /* /********************************************************** /* Type serialization methods /********************************************************** */ /** * Method called to write initial part of type information for given * value, when it will be output as scalar JSON value (not as JSON * Object or Array). * This means that the context after call can not be that of JSON Object; * it may be Array or root context. * * @param value Value that will be serialized, for which type information is * to be written * @param jgen Generator to use for writing type information */ public abstract void writeTypePrefixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException; /** * Method called to write initial part of type information for given * value, when it will be output as JSON Object value (not as JSON * Array or scalar). * This means that context after call must be JSON Object, meaning that * caller can then proceed to output field entries. * * @param value Value that will be serialized, for which type information is * to be written * @param jgen Generator to use for writing type information */ public abstract void writeTypePrefixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException; /** * Method called to write initial part of type information for given * value, when it will be output as JSON Array value (not as JSON * Object or scalar). * This means that context after call must be JSON Array, that is, there * must be an open START_ARRAY to write contents in. * * @param value Value that will be serialized, for which type information is * to be written * @param jgen Generator to use for writing type information */ public abstract void writeTypePrefixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException; /** * Method called after value has been serialized, to close any scopes opened * by earlier matching call to {@link #writeTypePrefixForScalar}. * Actual action to take may depend on various factors, but has to match with * action {@link #writeTypePrefixForScalar} did (close array or object; or do nothing). */ public abstract void writeTypeSuffixForScalar(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException; /** * Method called after value has been serialized, to close any scopes opened * by earlier matching call to {@link #writeTypePrefixForObject}. * It needs to write closing END_OBJECT marker, and any other decoration * that needs to be matched. */ public abstract void writeTypeSuffixForObject(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException; /** * Method called after value has been serialized, to close any scopes opened * by earlier matching call to {@link #writeTypeSuffixForScalar}. * It needs to write closing END_ARRAY marker, and any other decoration * that needs to be matched. */ public abstract void writeTypeSuffixForArray(Object value, JsonGenerator jgen) throws IOException, JsonProcessingException; /** * Alternative version of the prefix-for-scalar method, which is given * actual type to use (instead of using exact type of the value); typically * a super type of actual value type * * @since 1.8 */ public void writeTypePrefixForScalar(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { writeTypePrefixForScalar(value, jgen); } /** * Alternative version of the prefix-for-object method, which is given * actual type to use (instead of using exact type of the value); typically * a super type of actual value type * * @since 1.8 */ public void writeTypePrefixForObject(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { writeTypePrefixForObject(value, jgen); } /** * Alternative version of the prefix-for-array method, which is given * actual type to use (instead of using exact type of the value); typically * a super type of actual value type * * @since 1.8 */ public void writeTypePrefixForArray(Object value, JsonGenerator jgen, Class type) throws IOException, JsonProcessingException { writeTypePrefixForArray(value, jgen); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/HandlerInstantiator.java0000644000175000017500000001221011655120726031016 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.map.deser.ValueInstantiator; import org.codehaus.jackson.map.introspect.Annotated; import org.codehaus.jackson.map.jsontype.TypeIdResolver; import org.codehaus.jackson.map.jsontype.TypeResolverBuilder; /** * Helper class used for handling details of creating handler instances (things * like {@link JsonSerializer}s, {@link JsonDeserializer}s, various type * handlers) of specific types. Actual handler type has been resolved at this * point, so instantiator is strictly responsible for providing a configured * instance by constructing and configuring a new instance, or possibly by * recycling a shared instance. One use case is that of allowing * dependency injection, which would otherwise be difficult to do. *

* Custom instances are allowed to return null to indicate that caller should * use the default instantiation handling (which just means calling no-argument * constructor via reflection). *

* Care has to be taken to ensure that if instance returned is shared, it will * be thread-safe; caller will not synchronize access to returned instances. * * @since 1.8 */ public abstract class HandlerInstantiator { /* /********************************************************** /* Public API /********************************************************** */ /** * Method called to get an instance of deserializer of specified type. * * @param config Deserialization configuration in effect * @param annotated Element (Class, Method, Field, constructor parameter) that * had annotation defining class of deserializer to construct (to allow * implementation use information from other annotations) * @param deserClass Class of deserializer instance to return * * @return Deserializer instance to use */ public abstract JsonDeserializer deserializerInstance(DeserializationConfig config, Annotated annotated, Class> deserClass); /** * Method called to get an instance of key deserializer of specified type. * * @param config Deserialization configuration in effect * @param annotated Element (Class, Method, Field, constructor parameter) that * had annotation defining class of key deserializer to construct (to allow * implementation use information from other annotations) * @param keyDeserClass Class of key deserializer instance to return * * @return Key deserializer instance to use */ public abstract KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated, Class keyDeserClass); /** * Method called to get an instance of serializer of specified type. * * @param config Serialization configuration in effect * @param annotated Element (Class, Method, Field) that * had annotation defining class of serializer to construct (to allow * implementation use information from other annotations) * @param serClass Class of serializer instance to return * * @return Serializer instance to use */ public abstract JsonSerializer serializerInstance(SerializationConfig config, Annotated annotated, Class> serClass); /** * Method called to get an instance of TypeResolverBuilder of specified type. * * @param config Mapper configuration in effect (either SerializationConfig or * DeserializationConfig, depending on when instance is being constructed) * @param annotated annotated Element (Class, Method, Field) that * had annotation defining class of builder to construct (to allow * implementation use information from other annotations) * @param builderClass Class of builder instance to return * * @return TypeResolverBuilder instance to use */ public abstract TypeResolverBuilder typeResolverBuilderInstance(MapperConfig config, Annotated annotated, Class> builderClass); /** * Method called to get an instance of TypeIdResolver of specified type. * * @param config Mapper configuration in effect (either SerializationConfig or * DeserializationConfig, depending on when instance is being constructed) * @param annotated annotated Element (Class, Method, Field) that * had annotation defining class of resolver to construct (to allow * implementation use information from other annotations) * @param resolverClass Class of resolver instance to return * * @return TypeResolverBuilder instance to use */ public abstract TypeIdResolver typeIdResolverInstance(MapperConfig config, Annotated annotated, Class resolverClass); /** * Method called to construct an instance of ValueInstantiator of specified type. * * @since 1.9 */ public ValueInstantiator valueInstantiatorInstance(MapperConfig config, Annotated annotated, Class resolverClass) { return null; } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ObjectReader.java0000644000175000017500000006261111655120726027404 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.*; import java.net.URL; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import org.codehaus.jackson.*; import org.codehaus.jackson.io.SerializedString; import org.codehaus.jackson.map.deser.StdDeserializationContext; import org.codehaus.jackson.map.type.SimpleType; import org.codehaus.jackson.node.JsonNodeFactory; import org.codehaus.jackson.node.NullNode; import org.codehaus.jackson.node.TreeTraversingParser; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.TypeReference; import org.codehaus.jackson.util.VersionUtil; /** * Builder object that can be used for per-serialization configuration of * deserialization parameters, such as root type to use or object * to update (instead of constructing new instance). * Uses "fluid" (aka builder) pattern so that instances are immutable * (and thus fully thread-safe with no external synchronization); * new instances are constructed for different configurations. * Instances are initially constructed by {@link ObjectMapper} and can be * reused. * * @author tatu * @since 1.6 */ public class ObjectReader extends ObjectCodec implements Versioned { private final static JavaType JSON_NODE_TYPE = SimpleType.constructUnsafe(JsonNode.class); /* /********************************************************** /* Immutable configuration from ObjectMapper /********************************************************** */ /** * General serialization configuration settings; while immutable, * can use copy-constructor to create modified instances as necessary. */ protected final DeserializationConfig _config; /** * Flag that indicates whether root values are expected to be unwrapped * or not * * @since 1.9 */ protected final boolean _unwrapRoot; /** * Root-level cached deserializers */ final protected ConcurrentHashMap> _rootDeserializers; protected final DeserializerProvider _provider; /** * Factory used for constructing {@link JsonGenerator}s */ protected final JsonFactory _jsonFactory; /* /********************************************************** /* Configuration that can be changed during building /********************************************************** */ /** * Declared type of value to instantiate during deserialization. * Defines which deserializer to use; as well as base type of instance * to construct if an updatable value is not configured to be used * (subject to changes by embedded type information, for polymorphic * types). If {@link #_valueToUpdate} is non-null, only used for * locating deserializer. */ protected final JavaType _valueType; /** * Instance to update with data binding; if any. If null, * a new instance is created, if non-null, properties of * this value object will be updated instead. * Note that value can be of almost any type, except not * {@link org.codehaus.jackson.map.type.ArrayType}; array * types can not be modified because array size is immutable. */ protected final Object _valueToUpdate; /** * When using data format that uses a schema, schema is passed * to parser. * * @since 1.8 */ protected final FormatSchema _schema; /** * Values that can be injected during deserialization, if any. * * @since 1.9 */ protected final InjectableValues _injectableValues; /* /********************************************************** /* Life-cycle /********************************************************** */ /** * Constructor used by {@link ObjectMapper} for initial instantiation * * @since 1.8 */ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config) { this(mapper, config, null, null, null, null); } protected ObjectReader(ObjectMapper mapper, DeserializationConfig config, JavaType valueType, Object valueToUpdate, FormatSchema schema, InjectableValues injectableValues) { _config = config; _rootDeserializers = mapper._rootDeserializers; _provider = mapper._deserializerProvider; _jsonFactory = mapper._jsonFactory; _valueType = valueType; _valueToUpdate = valueToUpdate; if (valueToUpdate != null && valueType.isArrayType()) { throw new IllegalArgumentException("Can not update an array value"); } _schema = schema; _injectableValues = injectableValues; _unwrapRoot = config.isEnabled(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE); } /** * Copy constructor used for building variations. */ protected ObjectReader(ObjectReader base, DeserializationConfig config, JavaType valueType, Object valueToUpdate, FormatSchema schema, InjectableValues injectableValues) { _config = config; _rootDeserializers = base._rootDeserializers; _provider = base._provider; _jsonFactory = base._jsonFactory; _valueType = valueType; _valueToUpdate = valueToUpdate; if (valueToUpdate != null && valueType.isArrayType()) { throw new IllegalArgumentException("Can not update an array value"); } _schema = schema; _injectableValues = injectableValues; _unwrapRoot = config.isEnabled(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE); } /** * Method that will return version information stored in and read from jar * that contains this class. * * @since 1.6 */ @Override public Version version() { return VersionUtil.versionFor(getClass()); } public ObjectReader withType(JavaType valueType) { if (valueType == _valueType) return this; // type is stored here, no need to make a copy of config return new ObjectReader(this, _config, valueType, _valueToUpdate, _schema, _injectableValues); } public ObjectReader withType(Class valueType) { return withType(_config.constructType(valueType)); } public ObjectReader withType(java.lang.reflect.Type valueType) { return withType(_config.getTypeFactory().constructType(valueType)); } /** * @since 1.8 */ public ObjectReader withType(TypeReference valueTypeRef) { return withType(_config.getTypeFactory().constructType(valueTypeRef.getType())); } public ObjectReader withNodeFactory(JsonNodeFactory f) { // node factory is stored within config, so need to copy that first if (f == _config.getNodeFactory()) return this; return new ObjectReader(this, _config.withNodeFactory(f), _valueType, _valueToUpdate, _schema, _injectableValues); } public ObjectReader withValueToUpdate(Object value) { if (value == _valueToUpdate) return this; if (value == null) { throw new IllegalArgumentException("cat not update null value"); } JavaType t = _config.constructType(value.getClass()); return new ObjectReader(this, _config, t, value, _schema, _injectableValues); } /** * @since 1.8 */ public ObjectReader withSchema(FormatSchema schema) { if (_schema == schema) { return this; } return new ObjectReader(this, _config, _valueType, _valueToUpdate, schema, _injectableValues); } /** * @since 1.9 */ public ObjectReader withInjectableValues(InjectableValues injectableValues) { if (_injectableValues == injectableValues) { return this; } return new ObjectReader(this, _config, _valueType, _valueToUpdate, _schema, injectableValues); } /* /********************************************************** /* Deserialization methods; basic ones to support ObjectCodec first /* (ones that take JsonParser) /********************************************************** */ // not part of ObjectCodec, actually @SuppressWarnings("unchecked") public T readValue(JsonParser jp) throws IOException, JsonProcessingException { return (T) _bind(jp); } @SuppressWarnings("unchecked") @Override public T readValue(JsonParser jp, Class valueType) throws IOException, JsonProcessingException { return (T) withType(valueType).readValue(jp); } @SuppressWarnings("unchecked") @Override public T readValue(JsonParser jp, TypeReference valueTypeRef) throws IOException, JsonProcessingException { return (T) withType(valueTypeRef).readValue(jp); } @SuppressWarnings("unchecked") @Override public T readValue(JsonParser jp, JavaType valueType) throws IOException, JsonProcessingException { return (T) withType(valueType).readValue(jp); } @Override public JsonNode readTree(JsonParser jp) throws IOException, JsonProcessingException { return _bindAsTree(jp); } @Override public Iterator readValues(JsonParser jp, Class valueType) throws IOException, JsonProcessingException { return withType(valueType).readValues(jp); } @Override public Iterator readValues(JsonParser jp, TypeReference valueTypeRef) throws IOException, JsonProcessingException { return withType(valueTypeRef).readValues(jp); } @Override public Iterator readValues(JsonParser jp, JavaType valueType) throws IOException, JsonProcessingException { return withType(valueType).readValues(jp); } /* /********************************************************** /* Deserialization methods; others similar to what ObjectMapper has /********************************************************** */ @SuppressWarnings("unchecked") public T readValue(InputStream src) throws IOException, JsonProcessingException { return (T) _bindAndClose(_jsonFactory.createJsonParser(src)); } @SuppressWarnings("unchecked") public T readValue(Reader src) throws IOException, JsonProcessingException { return (T) _bindAndClose(_jsonFactory.createJsonParser(src)); } @SuppressWarnings("unchecked") public T readValue(String src) throws IOException, JsonProcessingException { return (T) _bindAndClose(_jsonFactory.createJsonParser(src)); } @SuppressWarnings("unchecked") public T readValue(byte[] src) throws IOException, JsonProcessingException { return (T) _bindAndClose(_jsonFactory.createJsonParser(src)); } @SuppressWarnings("unchecked") public T readValue(byte[] src, int offset, int length) throws IOException, JsonProcessingException { return (T) _bindAndClose(_jsonFactory.createJsonParser(src, offset, length)); } @SuppressWarnings("unchecked") public T readValue(File src) throws IOException, JsonProcessingException { return (T) _bindAndClose(_jsonFactory.createJsonParser(src)); } @SuppressWarnings("unchecked") public T readValue(URL src) throws IOException, JsonProcessingException { return (T) _bindAndClose(_jsonFactory.createJsonParser(src)); } /** * Convenience method for converting results from given JSON tree into given * value type. Basically short-cut for: *

     *   objectReader.readValue(src.traverse())
     *
*/ @SuppressWarnings("unchecked") public T readValue(JsonNode src) throws IOException, JsonProcessingException { return (T) _bindAndClose(treeAsTokens(src)); } public JsonNode readTree(InputStream in) throws IOException, JsonProcessingException { return _bindAndCloseAsTree(_jsonFactory.createJsonParser(in)); } public JsonNode readTree(Reader r) throws IOException, JsonProcessingException { return _bindAndCloseAsTree(_jsonFactory.createJsonParser(r)); } public JsonNode readTree(String content) throws IOException, JsonProcessingException { return _bindAndCloseAsTree(_jsonFactory.createJsonParser(content)); } /* /********************************************************** /* Deserialization methods; reading sequence of values /********************************************************** */ /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ public MappingIterator readValues(JsonParser jp) throws IOException, JsonProcessingException { DeserializationContext ctxt = _createDeserializationContext(jp, _config); return new MappingIterator(_valueType, jp, ctxt, _findRootDeserializer(_config, _valueType)); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ public MappingIterator readValues(InputStream src) throws IOException, JsonProcessingException { JsonParser jp = _jsonFactory.createJsonParser(src); if (_schema != null) { jp.setSchema(_schema); } DeserializationContext ctxt = _createDeserializationContext(jp, _config); return new MappingIterator(_valueType, jp, ctxt, _findRootDeserializer(_config, _valueType)); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ public MappingIterator readValues(Reader src) throws IOException, JsonProcessingException { JsonParser jp = _jsonFactory.createJsonParser(src); if (_schema != null) { jp.setSchema(_schema); } DeserializationContext ctxt = _createDeserializationContext(jp, _config); return new MappingIterator(_valueType, jp, ctxt, _findRootDeserializer(_config, _valueType)); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ public MappingIterator readValues(String json) throws IOException, JsonProcessingException { JsonParser jp = _jsonFactory.createJsonParser(json); if (_schema != null) { jp.setSchema(_schema); } DeserializationContext ctxt = _createDeserializationContext(jp, _config); return new MappingIterator(_valueType, jp, ctxt, _findRootDeserializer(_config, _valueType)); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ public MappingIterator readValues(byte[] src, int offset, int length) throws IOException, JsonProcessingException { JsonParser jp = _jsonFactory.createJsonParser(src, offset, length); if (_schema != null) { jp.setSchema(_schema); } DeserializationContext ctxt = _createDeserializationContext(jp, _config); return new MappingIterator(_valueType, jp, ctxt, _findRootDeserializer(_config, _valueType)); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ public MappingIterator readValues(File src) throws IOException, JsonProcessingException { JsonParser jp = _jsonFactory.createJsonParser(src); if (_schema != null) { jp.setSchema(_schema); } DeserializationContext ctxt = _createDeserializationContext(jp, _config); return new MappingIterator(_valueType, jp, ctxt, _findRootDeserializer(_config, _valueType)); } /** * Method for reading sequence of Objects from parser stream. * * @since 1.8 */ public MappingIterator readValues(URL src) throws IOException, JsonProcessingException { JsonParser jp = _jsonFactory.createJsonParser(src); if (_schema != null) { jp.setSchema(_schema); } DeserializationContext ctxt = _createDeserializationContext(jp, _config); return new MappingIterator(_valueType, jp, ctxt, _findRootDeserializer(_config, _valueType)); } /* /********************************************************** /* Helper methods /********************************************************** */ /** * Actual implementation of value reading+binding operation. */ protected Object _bind(JsonParser jp) throws IOException, JsonParseException, JsonMappingException { /* First: may need to read the next token, to initialize state (either * before first read from parser, or after previous token has been cleared) */ Object result; JsonToken t = _initForReading(jp); if (t == JsonToken.VALUE_NULL) { if (_valueToUpdate == null) { result = _findRootDeserializer(_config, _valueType).getNullValue(); } else { result = _valueToUpdate; } } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { result = _valueToUpdate; } else { // pointing to event other than null DeserializationContext ctxt = _createDeserializationContext(jp, _config); JsonDeserializer deser = _findRootDeserializer(_config, _valueType); if (_unwrapRoot) { result = _unwrapAndDeserialize(jp, ctxt, _valueType, deser); } else { if (_valueToUpdate == null) { result = deser.deserialize(jp, ctxt); } else { deser.deserialize(jp, ctxt, _valueToUpdate); result = _valueToUpdate; } } } // Need to consume the token too jp.clearCurrentToken(); return result; } protected Object _bindAndClose(JsonParser jp) throws IOException, JsonParseException, JsonMappingException { if (_schema != null) { jp.setSchema(_schema); } try { Object result; JsonToken t = _initForReading(jp); if (t == JsonToken.VALUE_NULL) { if (_valueToUpdate == null) { result = _findRootDeserializer(_config, _valueType).getNullValue(); } else { result = _valueToUpdate; } } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { result = _valueToUpdate; } else { DeserializationContext ctxt = _createDeserializationContext(jp, _config); JsonDeserializer deser = _findRootDeserializer(_config, _valueType); if (_unwrapRoot) { result = _unwrapAndDeserialize(jp, ctxt, _valueType, deser); } else { if (_valueToUpdate == null) { result = deser.deserialize(jp, ctxt); } else { deser.deserialize(jp, ctxt, _valueToUpdate); result = _valueToUpdate; } } } return result; } finally { try { jp.close(); } catch (IOException ioe) { } } } protected JsonNode _bindAsTree(JsonParser jp) throws IOException, JsonParseException, JsonMappingException { JsonNode result; JsonToken t = _initForReading(jp); if (t == JsonToken.VALUE_NULL || t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { result = NullNode.instance; } else { DeserializationContext ctxt = _createDeserializationContext(jp, _config); JsonDeserializer deser = _findRootDeserializer(_config, JSON_NODE_TYPE); if (_unwrapRoot) { result = (JsonNode) _unwrapAndDeserialize(jp, ctxt, JSON_NODE_TYPE, deser); } else { result = (JsonNode) deser.deserialize(jp, ctxt); } } // Need to consume the token too jp.clearCurrentToken(); return result; } protected JsonNode _bindAndCloseAsTree(JsonParser jp) throws IOException, JsonParseException, JsonMappingException { if (_schema != null) { jp.setSchema(_schema); } try { return _bindAsTree(jp); } finally { try { jp.close(); } catch (IOException ioe) { } } } protected static JsonToken _initForReading(JsonParser jp) throws IOException, JsonParseException, JsonMappingException { /* First: must point to a token; if not pointing to one, advance. * This occurs before first read from JsonParser, as well as * after clearing of current token. */ JsonToken t = jp.getCurrentToken(); if (t == null) { // and then we must get something... t = jp.nextToken(); if (t == null) { // [JACKSON-99] Should throw EOFException? throw new EOFException("No content to map to Object due to end of input"); } } return t; } /** * Method called to locate deserializer for the passed root-level value. */ protected JsonDeserializer _findRootDeserializer(DeserializationConfig cfg, JavaType valueType) throws JsonMappingException { // First: have we already seen it? JsonDeserializer deser = _rootDeserializers.get(valueType); if (deser != null) { return deser; } // Nope: need to ask provider to resolve it deser = _provider.findTypedValueDeserializer(cfg, valueType, null); if (deser == null) { // can this happen? throw new JsonMappingException("Can not find a deserializer for type "+valueType); } _rootDeserializers.put(valueType, deser); return deser; } protected DeserializationContext _createDeserializationContext(JsonParser jp, DeserializationConfig cfg) { // 04-Jan-2010, tatu: we do actually need the provider too... (for polymorphic deser) return new StdDeserializationContext(cfg, jp, _provider, _injectableValues); } protected Object _unwrapAndDeserialize(JsonParser jp, DeserializationContext ctxt, JavaType rootType, JsonDeserializer deser) throws IOException, JsonParseException, JsonMappingException { SerializedString rootName = _provider.findExpectedRootName(ctxt.getConfig(), rootType); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw JsonMappingException.from(jp, "Current token not START_OBJECT (needed to unwrap root name '" +rootName+"'), but "+jp.getCurrentToken()); } if (jp.nextToken() != JsonToken.FIELD_NAME) { throw JsonMappingException.from(jp, "Current token not FIELD_NAME (to contain expected root name '" +rootName+"'), but "+jp.getCurrentToken()); } String actualName = jp.getCurrentName(); if (!rootName.getValue().equals(actualName)) { throw JsonMappingException.from(jp, "Root name '"+actualName+"' does not match expected ('"+rootName +"') for type "+rootType); } // ok, then move to value itself.... jp.nextToken(); Object result; if (_valueToUpdate == null) { result = deser.deserialize(jp, ctxt); } else { deser.deserialize(jp, ctxt, _valueToUpdate); result = _valueToUpdate; } // and last, verify that we now get matching END_OBJECT if (jp.nextToken() != JsonToken.END_OBJECT) { throw JsonMappingException.from(jp, "Current token not END_OBJECT (to match wrapper object with root name '" +rootName+"'), but "+jp.getCurrentToken()); } return result; } /* /********************************************************** /* Implementation of rest of ObjectCodec methods /********************************************************** */ @Override public JsonNode createArrayNode() { return _config.getNodeFactory().arrayNode(); } @Override public JsonNode createObjectNode() { return _config.getNodeFactory().objectNode(); } @Override public JsonParser treeAsTokens(JsonNode n) { return new TreeTraversingParser(n, this); } @Override public T treeToValue(JsonNode n, Class valueType) throws IOException, JsonProcessingException { return readValue(treeAsTokens(n), valueType); } /** * NOTE: NOT implemented for {@link ObjectReader}. */ @Override public void writeTree(JsonGenerator jgen, JsonNode rootNode) throws IOException, JsonProcessingException { throw new UnsupportedOperationException("Not implemented for ObjectReader"); } @Override public void writeValue(JsonGenerator jgen, Object value) throws IOException, JsonProcessingException { throw new UnsupportedOperationException("Not implemented for ObjectReader"); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/InjectableValues.java0000644000175000017500000000563611655120726030277 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.util.*; /** * Abstract class that defines API for objects that provide value to * "inject" during deserialization. An instance of this object * * @since 1.9 */ public abstract class InjectableValues { /** * Method called to find value identified by id valueId to * inject as value of specified property during deserialization, passing * POJO instance in which value will be injected if it is available * (will be available when injected via field or setter; not available * when injected via constructor or factory method argument). * * @param valueId Object that identifies value to inject; may be a simple * name or more complex identifier object, whatever provider needs * @param ctxt Deserialization context * @param forProperty Bean property in which value is to be injected * @param beanInstance Bean instance that contains property to inject, * if available; null if bean has not yet been constructed. */ public abstract Object findInjectableValue(Object valueId, DeserializationContext ctxt, BeanProperty forProperty, Object beanInstance); /* /********************************************************** /* Standard implementation /********************************************************** */ /** * Simple standard implementation which uses a simple Map to * store values to inject, identified by simple String keys. */ public static class Std extends InjectableValues { protected final Map _values; public Std() { this(new HashMap()); } public Std(Map values) { _values = values; } public Std addValue(String key, Object value) { _values.put(key, value); return this; } public Std addValue(Class classKey, Object value) { _values.put(classKey.getName(), value); return this; } @Override public Object findInjectableValue(Object valueId, DeserializationContext ctxt, BeanProperty forProperty, Object beanInstance) { if (!(valueId instanceof String)) { String type = (valueId == null) ? "[null]" : valueId.getClass().getName(); throw new IllegalArgumentException("Unrecognized inject value id type ("+type+"), expecting String"); } String key = (String) valueId; Object ob = _values.get(key); if (ob == null && !_values.containsKey(key)) { throw new IllegalArgumentException("No injectable id with value '"+key+"' found (for property '" +forProperty.getName()+"')"); } return ob; } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/JsonSerializer.java0000644000175000017500000001171511655120726030015 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.IOException; import org.codehaus.jackson.*; /** * Abstract class that defines API used by {@link ObjectMapper} (and * other chained {@link JsonSerializer}s too) to serialize Objects of * arbitrary types into JSON, using provided {@link JsonGenerator}. *

* NOTE: it is recommended that custom serializers extend * {@link org.codehaus.jackson.map.ser.std.SerializerBase} instead * of this class, since it will implement many of optional * methods of this class. */ public abstract class JsonSerializer { /* /********************************************************** /* Fluent factory methods for constructing decorated versions /********************************************************** */ /** * Method that will return serializer instance that produces * "unwrapped" serialization, if applicable for type being * serialized (which is the case for some serializers * that produce JSON Objects as output). * If no unwrapped serializer can be constructed, will simply * return serializer as-is. *

* Default implementation just returns serializer as-is, * indicating that no unwrapped variant exists * * @since 1.9 */ public JsonSerializer unwrappingSerializer() { return this; } /** * Accessor for checking whether this serializer is an * "unwrapping" serializer; this is necessary to know since * it may also require caller to suppress writing of the * leading property name. * * @since 1.9 */ public boolean isUnwrappingSerializer() { return false; } /* /********************************************************** /* Serialization methods /********************************************************** */ /** * Method that can be called to ask implementation to serialize * values of type this serializer handles. * * @param value Value to serialize; can not be null. * @param jgen Generator used to output resulting Json content * @param provider Provider that can be used to get serializers for * serializing Objects value contains, if any. */ public abstract void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException; /** * Method that can be called to ask implementation to serialize * values of type this serializer handles, using specified type serializer * for embedding necessary type information. *

* Default implementation will ignore serialization of type information, * and just calls {@link #serialize}: serializers that can embed * type information should override this to implement actual handling. * Most common such handling is done by something like: *

     *  // note: method to call depends on whether this type is serialized as JSON scalar, object or Array!
     *  typeSer.writeTypePrefixForScalar(value, jgen);
     *  serialize(value, jgen, provider);
     *  typeSer.writeTypeSuffixForScalar(value, jgen);
     *
* * @param value Value to serialize; can not be null. * @param jgen Generator used to output resulting Json content * @param provider Provider that can be used to get serializers for * serializing Objects value contains, if any. * @param typeSer Type serializer to use for including type information * * @since 1.5 */ public void serializeWithType(T value, JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer) throws IOException, JsonProcessingException { serialize(value, jgen, provider); } /* /********************************************************** /* Introspection methods needed for type handling /********************************************************** */ /** * Method for accessing type of Objects this serializer can handle. * Note that this information is not guaranteed to be exact -- it * may be a more generic (super-type) -- but it should not be * incorrect (return a non-related type). *

* Default implementation will return null, which essentially means * same as returning Object.class would; that is, that * nothing is known about handled type. *

*/ public Class handledType() { return null; } /* /********************************************************** /* Helper class(es) /********************************************************** */ /** * This marker class is only to be used with annotations, to * indicate that no serializer is configured. *

* Specifically, this class is to be used as the marker for * annotation {@link org.codehaus.jackson.map.annotate.JsonSerialize}. */ public abstract static class None extends JsonSerializer { } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ContextualSerializer.java0000644000175000017500000000322411655120726031226 0ustar jamespagejamespagepackage org.codehaus.jackson.map; /** * Add-on interface that {@link JsonSerializer}s can implement to get a callback * that can be used to create contextual instances of serializer to use for * handling properties of supported type. This can be useful * for serializers that can be configured by annotations, or should otherwise * have differing behavior depending on what kind of property is being serialized. * * @param Type of serializer to contextualize * * @since 1.7 */ public interface ContextualSerializer { /** * Method called to see if a different (or differently configured) serializer * is needed to serialize values of specified property. * Note that instance that this method is called on is typically shared one and * as a result method should NOT modify this instance but rather construct * and return a new instance. This instance should only be returned as-is, in case * it is already suitable for use. * * @param config Current serialization configuration * @param property Method or field that represents the property * (and is used to access value to serialize). * Should be available; but there may be cases where caller can not provide it and * null is passed instead (in which case impls usually pass 'this' serializer as is) * * @return Serializer to use for serializing values of specified property; * may be this instance or a new instance. * * @throws JsonMappingException */ public JsonSerializer createContextual(SerializationConfig config, BeanProperty property) throws JsonMappingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/JsonMappingException.java0000644000175000017500000002431711655120726031160 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import java.io.Serializable; import java.util.*; import org.codehaus.jackson.*; /** * Checked exception used to signal fatal problems with mapping of * content. *

* One additional feature is the ability to denote relevant path * of references (during serialization/deserialization) to help in * troubleshooting. */ public class JsonMappingException extends JsonProcessingException { private static final long serialVersionUID = 1L; /** * Let's limit length of reference chain, to limit damage in cases * of infinite recursion. */ final static int MAX_REFS_TO_LIST = 1000; /* /********************************************************** /* Helper classes /********************************************************** */ /** * Simple bean class used to contain references. References * can be added to indicate execution/reference path that * lead to the problem that caused this exception to be * thrown. */ public static class Reference implements Serializable { private static final long serialVersionUID = 1L; /** * Object through which reference was resolved. Can be either * actual instance (usually the case for serialization), or * Class (usually the case for deserialization). */ protected Object _from; /** * Name of field (for beans) or key (for Maps) that is part * of the reference. May be null for Collection types (which * generally have {@link #_index} defined), or when resolving * Map classes without (yet) having an instance to operate on. */ protected String _fieldName; /** * Index within a {@link Collection} instance that contained * the reference; used if index is relevant and available. * If either not applicable, or not available, -1 is used to * denote "not known". */ protected int _index = -1; /** * Default constructor for deserialization/sub-classing purposes */ protected Reference() { } public Reference(Object from) { _from = from; } public Reference(Object from, String fieldName) { _from = from; if (fieldName == null) { throw new NullPointerException("Can not pass null fieldName"); } _fieldName = fieldName; } public Reference(Object from, int index) { _from = from; _index = index; } public void setFrom(Object o) { _from = o; } public void setFieldName(String n) { _fieldName = n; } public void setIndex(int ix) { _index = ix; } public Object getFrom() { return _from; } public String getFieldName() { return _fieldName; } public int getIndex() { return _index; } @Override public String toString() { StringBuilder sb = new StringBuilder(); Class cls = (_from instanceof Class) ? ((Class)_from) : _from.getClass(); /* Hmmh. Although Class.getName() is mostly ok, it does look * butt-ugly for arrays. So let's use getSimpleName() instead; * but have to prepend package name too. */ Package pkg = cls.getPackage(); if (pkg != null) { sb.append(pkg.getName()); sb.append('.'); } sb.append(cls.getSimpleName()); sb.append('['); if (_fieldName != null) { sb.append('"'); sb.append(_fieldName); sb.append('"'); } else if (_index >= 0) { sb.append(_index); } else { sb.append('?'); } sb.append(']'); return sb.toString(); } } /* /********************************************************** /* State/configuration /********************************************************** */ /** * Path through which problem that triggering throwing of * this exception was reached. */ protected LinkedList _path; /* /********************************************************** /* Life-cycle /********************************************************** */ public JsonMappingException(String msg) { super(msg); } public JsonMappingException(String msg, Throwable rootCause) { super(msg, rootCause); } public JsonMappingException(String msg, JsonLocation loc) { super(msg, loc); } public JsonMappingException(String msg, JsonLocation loc, Throwable rootCause) { super(msg, loc, rootCause); } public static JsonMappingException from(JsonParser jp, String msg) { return new JsonMappingException(msg, jp.getTokenLocation()); } public static JsonMappingException from(JsonParser jp, String msg, Throwable problem) { return new JsonMappingException(msg, jp.getTokenLocation(), problem); } /** * Method that can be called to either create a new JsonMappingException * (if underlying exception is not a JsonMappingException), or augment * given exception with given path/reference information. * * This version of method is called when the reference is through a * non-indexed object, such as a Map or POJO/bean. */ public static JsonMappingException wrapWithPath(Throwable src, Object refFrom, String refFieldName) { return wrapWithPath(src, new Reference(refFrom, refFieldName)); } /** * Method that can be called to either create a new JsonMappingException * (if underlying exception is not a JsonMappingException), or augment * given exception with given path/reference information. * * This version of method is called when the reference is through an * index, which happens with arrays and Collections. */ public static JsonMappingException wrapWithPath(Throwable src, Object refFrom, int index) { return wrapWithPath(src, new Reference(refFrom, index)); } /** * Method that can be called to either create a new JsonMappingException * (if underlying exception is not a JsonMappingException), or augment * given exception with given path/reference information. */ public static JsonMappingException wrapWithPath(Throwable src, Reference ref) { JsonMappingException jme; if (src instanceof JsonMappingException) { jme = (JsonMappingException) src; } else { String msg = src.getMessage(); /* Related to [JACKSON-62], let's use a more meaningful placeholder * if all we have is null */ if (msg == null || msg.length() == 0) { msg = "(was "+src.getClass().getName()+")"; } jme = new JsonMappingException(msg, null, src); } jme.prependPath(ref); return jme; } /* /********************************************************** /* Accessors/mutators /********************************************************** */ public List getPath() { if (_path == null) { return Collections.emptyList(); } return Collections.unmodifiableList(_path); } /** * Method called to prepend a reference information in front of * current path */ public void prependPath(Object referrer, String fieldName) { Reference ref = new Reference(referrer, fieldName); prependPath(ref); } /** * Method called to prepend a reference information in front of * current path */ public void prependPath(Object referrer, int index) { Reference ref = new Reference(referrer, index); prependPath(ref); } public void prependPath(Reference r) { if (_path == null) { _path = new LinkedList(); } /* Also: let's not increase without bounds. Could choose either * head or tail; tail is easier (no need to ever remove), as * well as potentially more useful so let's use it: */ if (_path.size() < MAX_REFS_TO_LIST) { _path.addFirst(r); } } /* /********************************************************** /* Overridden methods /********************************************************** */ /** * Method is overridden so that we can properly inject description * of problem path, if such is defined. */ @Override public String getMessage() { /* First: if we have no path info, let's just use parent's * definition as is */ String msg = super.getMessage(); if (_path == null) { return msg; } /* 19-Feb-2009, tatu: Null and empty messages are not very * useful (plus nulls would lead to NPEs), so let's * use something else */ StringBuilder sb = (msg == null) ? new StringBuilder() : new StringBuilder(msg); /* 18-Feb-2009, tatu: initially there was a linefeed between * message and path reference; but unfortunately many systems * (loggers, junit) seem to assume linefeeds are only added to * separate stack trace. */ sb.append(" (through reference chain: "); _appendPathDesc(sb); sb.append(')'); return sb.toString(); } @Override public String toString() { return getClass().getName()+": "+getMessage(); } /* /********************************************************** /* Internal methods /********************************************************** */ protected void _appendPathDesc(StringBuilder sb) { Iterator it = _path.iterator(); while (it.hasNext()) { sb.append(it.next().toString()); if (it.hasNext()) { sb.append("->"); } } } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/MappingJsonFactory.java0000644000175000017500000000444111655120726030625 0ustar jamespagejamespage/* Jackson JSON-processor. * * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi * * Licensed under the License specified in file LICENSE, included with * the source code and binary code bundles. * You may not use this file except in compliance with the License. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.jackson.map; import java.io.IOException; import org.codehaus.jackson.*; import org.codehaus.jackson.format.InputAccessor; import org.codehaus.jackson.format.MatchStrength; /** * Sub-class of {@link JsonFactory} that will create a proper * {@link ObjectCodec} to allow seamless conversions between * Json content and Java objects (POJOs). * The only addition to regular {@link JsonFactory} currently * is that {@link ObjectMapper} is constructed and passed as * the codec to use. */ public class MappingJsonFactory extends JsonFactory { public MappingJsonFactory() { this(null); } public MappingJsonFactory(ObjectMapper mapper) { super(mapper); if (mapper == null) { setCodec(new ObjectMapper(this)); } } /** * We'll override the method to return more specific type; co-variance * helps here */ @Override public final ObjectMapper getCodec() { return (ObjectMapper) _objectCodec; } /* /********************************************************** /* Format detection functionality (since 1.8) /********************************************************** */ /** * Sub-classes need to override this method (as of 1.8) */ @Override public String getFormatName() { /* since non-JSON factories typically should not extend this class, * let's just always return JSON as name. */ return FORMAT_NAME_JSON; } /** * Sub-classes need to override this method (as of 1.8) */ @Override public MatchStrength hasFormat(InputAccessor acc) throws IOException { return hasJSONFormat(acc); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/Deserializers.java0000644000175000017500000004344511655120726027664 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.type.*; import org.codehaus.jackson.type.JavaType; /** * Interface that defines API for simple extensions that can provide additional deserializers * for various types. Access is by a single callback method; instance is to either return * a configured {@link JsonDeserializer} for specified type, or null to indicate that it * does not support handling of the type. In latter case, further calls can be made * for other providers; in former case returned deserializer is used for handling of * instances of specified type. *

* Unlike with {@link Serializers}, multiple different methods are used since different * kinds of types typically require different kinds of inputs. * * @since 1.7 */ public interface Deserializers { /** * Method called to locate serializer for specified array type. *

* Deserializer for element type may be passed, if configured explicitly at higher level (by * annotations, typically), but usually are not. * Type deserializer for element is passed if one is needed based on contextual information * (annotations on declared element class; or on field or method type is associated with). * * @param type Type of array instances to deserialize * @param config Configuration in effect * @param provider Provider that can be used to locate deserializer for component type (if * one not provided, or needs to be overridden) * @param property Property that contains array value (null for root values) * @param elementTypeDeserializer If element type needs polymorphic type handling, this is * the type information deserializer to use; should usually be used as is when constructing * array deserializer. * @param elementDeserializer Deserializer to use for elements, if explicitly defined (by using * annotations, for exmple). May be null, in which case it should be resolved here (or using * {@link ResolvableDeserializer} callback) * * @return Deserializer to use for the type; or null if this provider does not know how to construct it */ public JsonDeserializer findArrayDeserializer(ArrayType type, DeserializationConfig config, DeserializerProvider provider, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException; /** * Method called to locate serializer for specified {@link java.util.Collection} (List, Set etc) type. *

* Deserializer for element type may be passed, if configured explicitly at higher level (by * annotations, typically), but usually are not. * Type deserializer for element is passed if one is needed based on contextual information * (annotations on declared element class; or on field or method type is associated with). * * @param type Type of collection instances to deserialize * @param config Configuration in effect * @param provider Provider that can be used to locate dependant deserializers if and as necessary * (but note that in many cases resolution must be deferred by using {@link ResolvableDeserializer} callback) * @param property Property that contains array value (null for root values) * @param beanDesc Definition of the enumeration type that contains class annotations and * other information typically needed for building deserializers (note: always instance * of {@link org.codehaus.jackson.map.introspect.BasicBeanDescription}) * @param elementTypeDeserializer If element type needs polymorphic type handling, this is * the type information deserializer to use; should usually be used as is when constructing * array deserializer. * @param elementDeserializer Deserializer to use for elements, if explicitly defined (by using * annotations, for exmple). May be null, in which case it should be resolved here (or using * {@link ResolvableDeserializer} callback) * * @return Deserializer to use for the type; or null if this provider does not know how to construct it */ public JsonDeserializer findCollectionDeserializer(CollectionType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException; /** * Method called to locate serializer for specified * "Collection-like" type (one that acts * like {@link java.util.Collection} but does not implement it). *

* Deserializer for element type may be passed, if configured explicitly at higher level (by * annotations, typically), but usually are not. * Type deserializer for element is passed if one is needed based on contextual information * (annotations on declared element class; or on field or method type is associated with). * * @param type Type of instances to deserialize * @param config Configuration in effect * @param provider Provider that can be used to locate dependant deserializers if and as necessary * (but note that in many cases resolution must be deferred by using {@link ResolvableDeserializer} callback) * @param property Property that contains array value (null for root values) * @param beanDesc Definition of the enumeration type that contains class annotations and * other information typically needed for building deserializers (note: always instance * of {@link org.codehaus.jackson.map.introspect.BasicBeanDescription}) * @param elementTypeDeserializer If element type needs polymorphic type handling, this is * the type information deserializer to use; should usually be used as is when constructing * array deserializer. * @param elementDeserializer Deserializer to use for elements, if explicitly defined (by using * annotations, for exmple). May be null, in which case it should be resolved here (or using * {@link ResolvableDeserializer} callback) * * @return Deserializer to use for the type; or null if this provider does not know how to construct it * * @since 1.8 */ public JsonDeserializer findCollectionLikeDeserializer(CollectionLikeType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException; /** * Method called to locate deserializer for specified {@link java.lang.Enum} type. * * @param type Type of {@link java.lang.Enum} instances to deserialize * @param config Configuration in effect * @param beanDesc Definition of the enumeration type that contains class annotations and * other information typically needed for building deserializers (note: always instance * of {@link org.codehaus.jackson.map.introspect.BasicBeanDescription}) * * @return Deserializer to use for the type; or null if this provider does not know how to construct it */ public JsonDeserializer findEnumDeserializer(Class type, DeserializationConfig config, BeanDescription beanDesc, BeanProperty property) throws JsonMappingException; /** * Method called to locate deserializer for specified {@link java.util.Map} type. *

* Deserializer for element type may be passed, if configured explicitly at higher level (by * annotations, typically), but usually are not. * Type deserializer for element is passed if one is needed based on contextual information * (annotations on declared element class; or on field or method type is associated with). *

* Similarly, a {@link KeyDeserializer} may be passed, but this is only done if there is * a specific configuration override (annotations) to indicate instance to use. Otherwise * null is passed, and key deserializer needs to be obtained using {@link DeserializerProvider} * * @param type Type of {@link java.util.Map} instances to deserialize * @param config Configuration in effect * @param provider Provider that can be used to locate dependant deserializers if and as necessary * (but note that in many cases resolution must be deferred by using {@link ResolvableDeserializer} callback) * @param beanDesc Definition of the enumeration type that contains class annotations and * other information typically needed for building deserializers (note: always instance * of {@link org.codehaus.jackson.map.introspect.BasicBeanDescription}) * @param keyDeserializer Key deserializer use, if it is defined via annotations or other configuration; * null if default key deserializer for key type can be used. * @param elementTypeDeserializer If element type needs polymorphic type handling, this is * the type information deserializer to use; should usually be used as is when constructing * array deserializer. * @param elementDeserializer Deserializer to use for elements, if explicitly defined (by using * annotations, for exmple). May be null, in which case it should be resolved here (or using * {@link ResolvableDeserializer} callback) * * @return Deserializer to use for the type; or null if this provider does not know how to construct it */ public JsonDeserializer findMapDeserializer(MapType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException; /** * Method called to locate serializer for specified * "Map-like" type (one that acts * like {@link java.util.Map} but does not implement it). *

* Deserializer for element type may be passed, if configured explicitly at higher level (by * annotations, typically), but usually are not. * Type deserializer for element is passed if one is needed based on contextual information * (annotations on declared element class; or on field or method type is associated with). *

* Similarly, a {@link KeyDeserializer} may be passed, but this is only done if there is * a specific configuration override (annotations) to indicate instance to use. Otherwise * null is passed, and key deserializer needs to be obtained using {@link DeserializerProvider} * * @param type Type of {@link java.util.Map} instances to deserialize * @param config Configuration in effect * @param provider Provider that can be used to locate dependant deserializers if and as necessary * (but note that in many cases resolution must be deferred by using {@link ResolvableDeserializer} callback) * @param beanDesc Definition of the enumeration type that contains class annotations and * other information typically needed for building deserializers (note: always instance * of {@link org.codehaus.jackson.map.introspect.BasicBeanDescription}) * @param keyDeserializer Key deserializer use, if it is defined via annotations or other configuration; * null if default key deserializer for key type can be used. * @param elementTypeDeserializer If element type needs polymorphic type handling, this is * the type information deserializer to use; should usually be used as is when constructing * array deserializer. * @param elementDeserializer Deserializer to use for elements, if explicitly defined (by using * annotations, for exmple). May be null, in which case it should be resolved here (or using * {@link ResolvableDeserializer} callback) * * @return Deserializer to use for the type; or null if this provider does not know how to construct it * * @since 1.8 */ public JsonDeserializer findMapLikeDeserializer(MapLikeType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException; /** * Method called to locate deserializer for specified JSON tree node type. * * @param nodeType Specific type of JSON tree nodes to deserialize (subtype of {@link org.codehaus.jackson.JsonNode}) * @param config Configuration in effect * * @return Deserializer to use for the type; or null if this provider does not know how to construct it */ public JsonDeserializer findTreeNodeDeserializer(Class nodeType, DeserializationConfig config, BeanProperty property) throws JsonMappingException; /** * Method called to locate deserializer for specified value type which does not belong to any other * category (not an Enum, Collection, Map, Array or tree node) * * @param type Bean type to deserialize * @param config Configuration in effect * @param provider Provider that can be used to locate dependant deserializers if and as necessary * (but note that in many cases resolution must be deferred by using {@link ResolvableDeserializer} callback) * @param beanDesc Definition of the enumeration type that contains class annotations and * other information typically needed for building deserializers (note: always instance * of {@link org.codehaus.jackson.map.introspect.BasicBeanDescription}) * * @return Deserializer to use for the type; or null if this provider does not know how to construct it */ public JsonDeserializer findBeanDeserializer(JavaType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property) throws JsonMappingException; /* /********************************************************** /* Helper classes /********************************************************** */ /** * Basic {@link Deserializers} implementation that implements all methods but provides * no deserializers. Its main purpose is to serve as a base class so that * sub-classes only need to override methods they need, as most of the time some * of methods are not needed (especially enumeration and array deserializers are * very rarely overridden). * * @since 1.9 */ public static class Base implements Deserializers { @Override public JsonDeserializer findArrayDeserializer(ArrayType type, DeserializationConfig config, DeserializerProvider provider, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return null; } @Override public JsonDeserializer findCollectionDeserializer(CollectionType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return null; } @Override public JsonDeserializer findCollectionLikeDeserializer(CollectionLikeType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return null; } @Override public JsonDeserializer findMapDeserializer(MapType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return null; } @Override public JsonDeserializer findMapLikeDeserializer(MapLikeType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer elementDeserializer) throws JsonMappingException { return null; } @Override public JsonDeserializer findEnumDeserializer(Class type, DeserializationConfig config, BeanDescription beanDesc, BeanProperty property) throws JsonMappingException { return null; } @Override public JsonDeserializer findTreeNodeDeserializer(Class nodeType, DeserializationConfig config, BeanProperty property) throws JsonMappingException { return null; } @Override public JsonDeserializer findBeanDeserializer(JavaType type, DeserializationConfig config, DeserializerProvider provider, BeanDescription beanDesc, BeanProperty property) throws JsonMappingException { return null; } } /** * @deprecated As of 1.9, use {@link Base} instead */ @Deprecated public static class None extends Base { } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ClassIntrospector.java0000644000175000017500000000762711655120726030542 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.type.JavaType; /** * Helper class used to introspect features of POJO value classes * used with Jackson. The main use is for finding out * POJO construction (creator) and value access (getters, setters) * methods and annotations that define configuration of using * those methods. */ public abstract class ClassIntrospector { /* /********************************************************** /* Helper interfaces /********************************************************** */ /** * Interface used for decoupling details of how mix-in annotation * definitions are accessed (via this interface), and how * they are stored (defined by classes that implement the interface) */ public interface MixInResolver { /** * Method that will check if there are "mix-in" classes (with mix-in * annotations) for given class */ public Class findMixInClassFor(Class cls); } protected ClassIntrospector() { } /* /********************************************************** /* Public API: factory methods /********************************************************** */ /** * Factory method that constructs an introspector that has all * information needed for serialization purposes. */ public abstract T forSerialization(SerializationConfig cfg, JavaType type, MixInResolver r); /** * Factory method that constructs an introspector that has all * information needed for deserialization purposes. */ public abstract T forDeserialization(DeserializationConfig cfg, JavaType type, MixInResolver r); /** * Factory method that constructs an introspector that has * information necessary for creating instances of given * class ("creator"), as well as class annotations, but * no information on member methods */ public abstract T forCreation(DeserializationConfig cfg, JavaType type, MixInResolver r); /** * Factory method that constructs an introspector that only has * information regarding annotations class itself (or its supertypes) has, * but nothing on methods or constructors. */ public abstract T forClassAnnotations(MapperConfig cfg, JavaType type, MixInResolver r); /** * Factory method that constructs an introspector that only has * information regarding annotations class itself has (but NOT including * its supertypes), but nothing on methods or constructors. * * @since 1.5 */ public abstract T forDirectClassAnnotations(MapperConfig cfg, JavaType type, MixInResolver r); /* /********************************************************** /* Deprecated methods /********************************************************** */ /** * Factory method that constructs an introspector that only has * information regarding annotations class itself (or its supertypes) has, * but nothing on methods or constructors. * * @deprecated since 1.9, use variant that takes JavaType */ @Deprecated public T forClassAnnotations(MapperConfig cfg, Class cls, MixInResolver r) { return forClassAnnotations(cfg, cfg.constructType(cls), r); } /** * Factory method that constructs an introspector that only has * information regarding annotations class itself has (but NOT including * its supertypes), but nothing on methods or constructors. * * @since 1.5 * * @deprecated since 1.9, use variant that takes JavaType */ @Deprecated public T forDirectClassAnnotations(MapperConfig cfg, Class cls, MixInResolver r) { return forDirectClassAnnotations(cfg, cfg.constructType(cls), r); } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/ContextualDeserializer.java0000644000175000017500000000330711655120726031541 0ustar jamespagejamespagepackage org.codehaus.jackson.map; /** * Add-on interface that {@link JsonDeserializer}s can implement to get a callback * that can be used to create contextual instances of deserializer to use for * handling properties of supported type. This can be useful * for deserializers that can be configured by annotations, or should otherwise * have differing behavior depending on what kind of property is being deserialized. * * @param Type of deserializer to contextualize * * @since 1.7 */ public interface ContextualDeserializer { /** * Method called to see if a different (or differently configured) deserializer * is needed to deserialize values of specified property. * Note that instance that this method is called on is typically shared one and * as a result method should NOT modify this instance but rather construct * and return a new instance. This instance should only be returned as-is, in case * it is already suitable for use. * * @param config Current deserialization configuration * @param property Method, field or constructor parameter that represents the property * (and is used to assign deserialized value). * Should be available; but there may be cases where caller can not provide it and * null is passed instead (in which case impls usually pass 'this' deserializer as is) * * @return Deserializer to use for deserializing values of specified property; * may be this instance or a new instance. * * @throws JsonMappingException */ public JsonDeserializer createContextual(DeserializationConfig config, BeanProperty property) throws JsonMappingException; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/Serializers.java0000644000175000017500000001330611655120726027344 0ustar jamespagejamespagepackage org.codehaus.jackson.map; import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.map.type.*; /** * Interface that defines API for simple extensions that can provide additional serializers * for various types. Access is by a single callback method; instance is to either return * a configured {@link JsonSerializer} for specified type, or null to indicate that it * does not support handling of the type. In latter case, further calls can be made * for other providers; in former case returned serializer is used for handling of * instances of specified type. * * @since 1.7 */ public interface Serializers { /** * Method called by serialization framework first time a serializer is needed for * specified type, which is not of a container type (for which other methods are * called). *

* Note: in version 1.7, this method was called to find serializers for all * type, including container types. * * @param type Fully resolved type of instances to serialize * @param config Serialization configuration in use * @param beanDesc Additional information about type; will always be of type * {@link org.codehaus.jackson.map.introspect.BasicBeanDescription} (that is, * safe to cast to this more specific type) * @param property Property that contains values to serialize * * @return Configured serializer to use for the type; or null if implementation * does not recognize or support type */ public JsonSerializer findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc, BeanProperty property); /** * Method called by serialization framework first time a serializer is needed for * specified array type. * Implementation should return a serializer instance if it supports * specified type; or null if it does not. * * @since 1.8 */ public JsonSerializer findArraySerializer(SerializationConfig config, ArrayType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer); public JsonSerializer findCollectionSerializer(SerializationConfig config, CollectionType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer); public JsonSerializer findCollectionLikeSerializer(SerializationConfig config, CollectionLikeType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer); public JsonSerializer findMapSerializer(SerializationConfig config, MapType type, BeanDescription beanDesc, BeanProperty property, JsonSerializer keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer); public JsonSerializer findMapLikeSerializer(SerializationConfig config, MapLikeType type, BeanDescription beanDesc, BeanProperty property, JsonSerializer keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer); /** * Basic {@link Serializers} implementation that implements all methods but provides * no serializers. Its main purpose is to serve as a base class so that * sub-classes only need to override methods they need. * * @since 1.9 */ public static class Base implements Serializers { @Override public JsonSerializer findSerializer(SerializationConfig config, JavaType type, BeanDescription beanDesc, BeanProperty property) { return null; } @Override public JsonSerializer findArraySerializer(SerializationConfig config, ArrayType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return null; } @Override public JsonSerializer findCollectionSerializer(SerializationConfig config, CollectionType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return null; } @Override public JsonSerializer findCollectionLikeSerializer(SerializationConfig config, CollectionLikeType type, BeanDescription beanDesc, BeanProperty property, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return null; } @Override public JsonSerializer findMapSerializer(SerializationConfig config, MapType type, BeanDescription beanDesc, BeanProperty property, JsonSerializer keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return null; } @Override public JsonSerializer findMapLikeSerializer(SerializationConfig config, MapLikeType type, BeanDescription beanDesc, BeanProperty property, JsonSerializer keySerializer, TypeSerializer elementTypeSerializer, JsonSerializer elementValueSerializer) { return null; } } /** * @deprecated As of 1.9, use {@link Base} instead */ @Deprecated public static class None extends Base { } } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/annotate/0000755000175000017500000000000011672662540026017 5ustar jamespagejamespagejackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/annotate/JacksonStdImpl.java0000644000175000017500000000143111655120726031542 0ustar jamespagejamespagepackage org.codehaus.jackson.map.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.codehaus.jackson.annotate.JacksonAnnotation; /** * Marker interface used to indicate implementation classes * (serializers, deserializers etc) that are standard ones Jackson * uses; not custom ones that application has added. It can be * added in cases where certain optimizations can be made if * default instances are uses; for example when handling conversions * of "natural" JSON types like Strings, booleans and numbers. * * @since 1.6 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JacksonStdImpl { } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/annotate/JsonValueInstantiator.java0000644000175000017500000000133511655120726033166 0ustar jamespagejamespagepackage org.codehaus.jackson.map.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.codehaus.jackson.annotate.JacksonAnnotation; import org.codehaus.jackson.map.deser.ValueInstantiator; /** * Annotation that can be used to indicate a {@link ValueInstantiator} to use * for creating instances of specified type. * * @since 1.9 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonValueInstantiator { /** * @return {@link ValueInstantiator} to use for annotated type */ public Class value(); } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/annotate/JacksonInject.java0000644000175000017500000000176411655120726031413 0ustar jamespagejamespagepackage org.codehaus.jackson.map.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.codehaus.jackson.annotate.JacksonAnnotation; /** * Jackson-specific annotation used for indicating that value of * annotated property will be "injected", i.e. set based on value * configured by ObjectMapper (usually on per-call basis). * Usually property is not deserialized from JSON, although it possible * to have injected value as default and still allow optional override * from JSON. * * @since 1.9 */ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JacksonInject { /** * Logical id of the value to inject; if not specified (or specified * as empty String), will use id based on declared type of property. */ public String value() default ""; } jackson-src-1.9.2/src/mapper/java/org/codehaus/jackson/map/annotate/JsonSerialize.java0000644000175000017500000001637511655120726031453 0ustar jamespagejamespagepackage org.codehaus.jackson.map.annotate; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.codehaus.jackson.annotate.JacksonAnnotation; import org.codehaus.jackson.map.*; /** * Annotation used for configuring serialization aspects, by attaching * to "getter" methods or fields, or to value classes. * When annotating value classes, configuration is used for instances * of the value class but can be overridden by more specific annotations * (ones that attach to methods or fields). *

* An example annotation would be: *

 *  @JsonSerialize(using=MySerializer.class,
 *    as=MySubClass.class,
 *    include=JsonSerialize.Inclusion.NON_NULL,
 *    typing=JsonSerialize.Typing.STATIC
 *  )
 *
* (which would be redundant, since some properties block others: * specifically, 'using' has precedence over 'as', which has precedence * over 'typing' setting) *

* NOTE: since version 1.2, annotation has also been applicable * to (constructor) parameters * * @since 1.1 */ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotation public @interface JsonSerialize { // // // Annotations for explicitly specifying deserializer /** * Serializer class to use for * serializing associated value. Depending on what is annotated, * value is either an instance of annotated class (used globablly * anywhere where class serializer is needed); or only used for * serializing property access via a getter method. */ public Class> using() default JsonSerializer.None.class; /** * Serializer class to use for serializing contents (elements * of a Collection/array, values of Maps) of annotated property. * Can only be used on properties (methods, fields, constructors), * and not value classes themselves (as they are typically generic) * * @since 1.8 */ public Class> contentUsing() default JsonSerializer.None.class; /** * Serializer class to use for serializing Map keys * of annotated property. * Can only be used on properties (methods, fields, constructors), * and not value classes themselves. * * @since 1.8 */ public Class> keyUsing() default JsonSerializer.None.class; // // // Annotations for type handling, explicit declaration // // // (type used for choosing deserializer, if not explicitly // // // specified) /** * Supertype (of declared type, which itself is supertype of runtime type) * to use as type when locating serializer to use. *

* Bogus type {@link NoClass} can be used to indicate that declared * type is used as is (i.e. this annotation property has no setting); * this since annotation properties are not allowed to have null value. *

* Note: if {@link #using} is also used it has precedence * (since it directly specifies * serializer, whereas this would only be used to locate the * serializer) * and value of this annotation property is ignored. */ public Class as() default NoClass.class; /** * Concrete type to serialize keys of {@link java.util.Map} as, * instead of type otherwise declared. * Must be a supertype of declared type; otherwise an exception may be * thrown by serializer. */ public Class keyAs() default NoClass.class; /** * Concrete type to serialize content value (elements * of a Collection/array, values of Maps) as, * instead of type otherwise declared. * Must be a supertype of declared type; otherwise an exception may be * thrown by serializer. */ public Class contentAs() default NoClass.class; /** * Whether type detection used is dynamic or static: that is, * whether actual runtime type is used (dynamic), or just the * declared type (static). * * @since 1.2 */ public Typing typing() default Typing.DYNAMIC; // // // Annotation(s) for inclusion criteria /** * Which properties of annotated Bean are * to be included in serialization (has no effect on other types * like enums, primitives or collections). * Choices are "all", "properties that have value other than null" * and "properties that have non-default value" (i.e. default value * being property setting for a Bean constructed with default no-arg * constructor, often null). * */ public Inclusion include() default Inclusion.ALWAYS; /* /********************************************************** /* Value enumerations needed /********************************************************** */ /** * Enumeration used with {@link JsonSerialize#include} property * to define which properties * of Java Beans are to be included in serialization * * @since 1.1 */ public enum Inclusion { /** * Value that indicates that properties are to be always included, * independent of value */ ALWAYS, /** * Value that indicates that only properties with non-null * values are to be included. */ NON_NULL, /** * Value that indicates that only properties that have values * that differ from default settings (meaning values they have * when Bean is constructed with its no-arguments constructor) * are to be included. Value is generally not useful with * {@link java.util.Map}s, since they have no default values; * and if used, works same as {@link #ALWAYS}. */ NON_DEFAULT, /** * Value that indicates that only properties that have values * that values that are null or what is considered empty are * not to be included. * Emptiness is defined for following type: *