blob: 8f32b5c6c2d62203e3efe98332027b26b7919095 [file] [log] [blame]
Tatu Salorantaf15531c2011-12-22 23:00:40 -08001package com.fasterxml.jackson.core.io;
2
Tatu Saloranta95f76a42012-10-05 13:04:23 -07003import java.io.*;
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -08004import java.nio.ByteBuffer;
5
Tatu Salorantaf15531c2011-12-22 23:00:40 -08006import com.fasterxml.jackson.core.SerializableString;
7
8/**
9 * String token that can lazily serialize String contained and then reuse that
10 * serialization later on. This is similar to JDBC prepared statements, for example,
11 * in that instances should only be created when they are used more than use;
12 * prime candidates are various serializers.
13 *<p>
14 * Class is final for performance reasons and since this is not designed to
15 * be extensible or customizable (customizations would occur in calling code)
Tatu Salorantaf15531c2011-12-22 23:00:40 -080016 */
Tatu Saloranta95f76a42012-10-05 13:04:23 -070017public class SerializedString
18 implements SerializableString, java.io.Serializable
Tatu Salorantaf15531c2011-12-22 23:00:40 -080019{
Tatu Salorantae962fb92016-07-21 14:14:26 -070020 private static final long serialVersionUID = 1L;
21
Tatu Salorantaf15531c2011-12-22 23:00:40 -080022 protected final String _value;
23
24 /* 13-Dec-2010, tatu: Whether use volatile or not is actually an important
25 * decision for multi-core use cases. Cost of volatility can be non-trivial
26 * for heavy use cases, and serialized-string instances are accessed often.
27 * Given that all code paths with common Jackson usage patterns go through
28 * a few memory barriers (mostly with cache/reuse pool access) it seems safe
29 * enough to omit volatiles here, given how simple lazy initialization is.
Tatu Saloranta8a42d5e2014-12-18 19:37:13 -080030 * This can be compared to how {@link String#hashCode} works; lazily and
Tatu Salorantaf15531c2011-12-22 23:00:40 -080031 * without synchronization or use of volatile keyword.
Tatu Salorantae15b9a82014-01-24 21:01:04 -080032 *
Tatu Saloranta066463a2013-09-22 19:57:25 -070033 * Change to remove volatile was a request by implementors of a high-throughput
34 * search framework; and they believed this is an important optimization for
35 * heaviest, multi-core deployed use cases.
36 */
37 /*
38 * 22-Sep-2013, tatu: FWIW, there have been no reports of problems in this
39 * area, or anything pointing to it. So I think we are safe up to JDK7
Tatu Salorantae15b9a82014-01-24 21:01:04 -080040 * and hopefully beyond.
Tatu Salorantaf15531c2011-12-22 23:00:40 -080041 */
42
43 protected /*volatile*/ byte[] _quotedUTF8Ref;
44
45 protected /*volatile*/ byte[] _unquotedUTF8Ref;
46
47 protected /*volatile*/ char[] _quotedChars;
48
Tatu Saloranta95f76a42012-10-05 13:04:23 -070049 public SerializedString(String v) {
50 if (v == null) {
51 throw new IllegalStateException("Null String illegal for SerializedString");
52 }
53 _value = v;
54 }
55
56 /*
57 /**********************************************************
58 /* Serializable overrides
59 /**********************************************************
60 */
61
62 /**
63 * Ugly hack, to work through the requirement that _value is indeed final,
64 * and that JDK serialization won't call ctor(s).
65 *
66 * @since 2.1
67 */
68 protected transient String _jdkSerializeValue;
69
70 private void readObject(ObjectInputStream in) throws IOException {
71 _jdkSerializeValue = in.readUTF();
72 }
73
74 private void writeObject(ObjectOutputStream out) throws IOException {
75 out.writeUTF(_value);
76 }
77
78 protected Object readResolve() {
79 return new SerializedString(_jdkSerializeValue);
80 }
Tatu Salorantaf15531c2011-12-22 23:00:40 -080081
82 /*
83 /**********************************************************
84 /* API
85 /**********************************************************
86 */
87
Tatu Saloranta12525982013-02-12 22:56:57 -080088 @Override
Tatu Salorantaf15531c2011-12-22 23:00:40 -080089 public final String getValue() { return _value; }
90
91 /**
92 * Returns length of the String as characters
93 */
Tatu Saloranta12525982013-02-12 22:56:57 -080094 @Override
Tatu Salorantaf15531c2011-12-22 23:00:40 -080095 public final int charLength() { return _value.length(); }
96
Tatu Saloranta12525982013-02-12 22:56:57 -080097 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -080098 public final char[] asQuotedChars() {
Tatu Salorantaf15531c2011-12-22 23:00:40 -080099 char[] result = _quotedChars;
100 if (result == null) {
101 result = JsonStringEncoder.getInstance().quoteAsString(_value);
102 _quotedChars = result;
103 }
104 return result;
105 }
106
107 /**
108 * Accessor for accessing value that has been quoted using JSON
109 * quoting rules, and encoded using UTF-8 encoding.
110 */
Tatu Saloranta12525982013-02-12 22:56:57 -0800111 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800112 public final byte[] asUnquotedUTF8() {
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800113 byte[] result = _unquotedUTF8Ref;
114 if (result == null) {
115 result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
116 _unquotedUTF8Ref = result;
117 }
118 return result;
119 }
120
121 /**
122 * Accessor for accessing value as is (without JSON quoting)
123 * encoded using UTF-8 encoding.
124 */
Tatu Saloranta12525982013-02-12 22:56:57 -0800125 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800126 public final byte[] asQuotedUTF8() {
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800127 byte[] result = _quotedUTF8Ref;
128 if (result == null) {
129 result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
130 _quotedUTF8Ref = result;
131 }
132 return result;
133 }
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800134
135 /*
136 /**********************************************************
137 /* Additional 2.0 methods for appending/writing contents
138 /**********************************************************
139 */
Tatu Salorantae9b48512012-04-17 10:22:07 -0700140
Tatu Saloranta12525982013-02-12 22:56:57 -0800141 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800142 public int appendQuotedUTF8(byte[] buffer, int offset) {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800143 byte[] result = _quotedUTF8Ref;
144 if (result == null) {
145 result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
146 _quotedUTF8Ref = result;
147 }
148 final int length = result.length;
149 if ((offset + length) > buffer.length) {
150 return -1;
151 }
152 System.arraycopy(result, 0, buffer, offset, length);
153 return length;
154 }
155
Tatu Saloranta12525982013-02-12 22:56:57 -0800156 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800157 public int appendQuoted(char[] buffer, int offset) {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800158 char[] result = _quotedChars;
159 if (result == null) {
160 result = JsonStringEncoder.getInstance().quoteAsString(_value);
161 _quotedChars = result;
162 }
163 final int length = result.length;
164 if ((offset + length) > buffer.length) {
165 return -1;
166 }
167 System.arraycopy(result, 0, buffer, offset, length);
168 return length;
169 }
170
Tatu Saloranta12525982013-02-12 22:56:57 -0800171 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800172 public int appendUnquotedUTF8(byte[] buffer, int offset) {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800173 byte[] result = _unquotedUTF8Ref;
174 if (result == null) {
175 result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
176 _unquotedUTF8Ref = result;
177 }
178 final int length = result.length;
179 if ((offset + length) > buffer.length) {
180 return -1;
181 }
182 System.arraycopy(result, 0, buffer, offset, length);
183 return length;
184 }
185
Tatu Saloranta12525982013-02-12 22:56:57 -0800186 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800187 public int appendUnquoted(char[] buffer, int offset) {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800188 String str = _value;
189 final int length = str.length();
190 if ((offset + length) > buffer.length) {
191 return -1;
192 }
193 str.getChars(0, length, buffer, offset);
194 return length;
195 }
196
Tatu Saloranta12525982013-02-12 22:56:57 -0800197 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800198 public int writeQuotedUTF8(OutputStream out) throws IOException {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800199 byte[] result = _quotedUTF8Ref;
200 if (result == null) {
201 result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
202 _quotedUTF8Ref = result;
203 }
204 final int length = result.length;
205 out.write(result, 0, length);
206 return length;
207 }
208
Tatu Saloranta12525982013-02-12 22:56:57 -0800209 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800210 public int writeUnquotedUTF8(OutputStream out) throws IOException {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800211 byte[] result = _unquotedUTF8Ref;
212 if (result == null) {
213 result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
214 _unquotedUTF8Ref = result;
215 }
216 final int length = result.length;
217 out.write(result, 0, length);
218 return length;
219 }
220
Tatu Saloranta12525982013-02-12 22:56:57 -0800221 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800222 public int putQuotedUTF8(ByteBuffer buffer) {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800223 byte[] result = _quotedUTF8Ref;
224 if (result == null) {
225 result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
226 _quotedUTF8Ref = result;
227 }
228 final int length = result.length;
229 if (length > buffer.remaining()) {
230 return -1;
231 }
232 buffer.put(result, 0, length);
233 return length;
234 }
235
Tatu Saloranta12525982013-02-12 22:56:57 -0800236 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800237 public int putUnquotedUTF8(ByteBuffer buffer) {
Tatu Saloranta0ccc4c92012-01-17 22:13:16 -0800238 byte[] result = _unquotedUTF8Ref;
239 if (result == null) {
240 result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
241 _unquotedUTF8Ref = result;
242 }
243 final int length = result.length;
244 if (length > buffer.remaining()) {
245 return -1;
246 }
247 buffer.put(result, 0, length);
248 return length;
249 }
250
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800251
252 /*
253 /**********************************************************
254 /* Standard method overrides
255 /**********************************************************
256 */
257
258 @Override
259 public final String toString() { return _value; }
260
261 @Override
262 public final int hashCode() { return _value.hashCode(); }
263
264 @Override
Tatu Salorantafe5b6982013-12-13 22:21:26 -0800265 public final boolean equals(Object o) {
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800266 if (o == this) return true;
267 if (o == null || o.getClass() != getClass()) return false;
268 SerializedString other = (SerializedString) o;
269 return _value.equals(other._value);
270 }
271}