package com.fasterxml.jackson.core.io;
import java.io.*;
import java.nio.ByteBuffer;
import com.fasterxml.jackson.core.SerializableString;
import com.fasterxml.jackson.core.util.BufferRecyclers;
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)
/**
* 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.
*<p>
* Class is final for performance reasons and since this is not designed to
* be extensible or customizable (customizations would occur in calling code)
*/
public class SerializedString
implements SerializableString, java.io.Serializable
{
private static final long serialVersionUID = 1L;
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#hashCode} works; lazily and
* without synchronization or use of volatile keyword.
*
* Change to remove volatile was a request by implementors of a high-throughput
* search framework; and they believed this is an important optimization for
* heaviest, multi-core deployed use cases.
*/
/*
* 22-Sep-2013, tatu: FWIW, there have been no reports of problems in this
* area, or anything pointing to it. So I think we are safe up to JDK7
* and hopefully beyond.
*/
protected /*volatile*/ byte[] _quotedUTF8Ref;
protected /*volatile*/ byte[] _unquotedUTF8Ref;
protected /*volatile*/ char[] _quotedChars;
public SerializedString(String v) {
if (v == null) {
throw new IllegalStateException("Null String illegal for SerializedString");
}
_value = v;
}
/*
/**********************************************************
/* Serializable overrides
/**********************************************************
*/
Ugly hack, to work through the requirement that _value is indeed final,
and that JDK serialization won't call ctor(s).
Since: 2.1
/**
* Ugly hack, to work through the requirement that _value is indeed final,
* and that JDK serialization won't call ctor(s).
*
* @since 2.1
*/
protected transient String _jdkSerializeValue;
private void readObject(ObjectInputStream in) throws IOException {
_jdkSerializeValue = in.readUTF();
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeUTF(_value);
}
protected Object readResolve() {
return new SerializedString(_jdkSerializeValue);
}
/*
/**********************************************************
/* API
/**********************************************************
*/
@Override
public final String getValue() { return _value; }
Returns length of the String as characters
/**
* 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 = BufferRecyclers.quoteAsJsonText(_value);
_quotedChars = result;
}
return result;
}
Accessor for accessing value that has been quoted using JSON
quoting rules, and encoded using UTF-8 encoding.
/**
* 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 = BufferRecyclers.encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
return result;
}
Accessor for accessing value as is (without JSON quoting)
encoded using UTF-8 encoding.
/**
* 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 = BufferRecyclers.quoteAsJsonUTF8(_value);
_quotedUTF8Ref = result;
}
return result;
}
/*
/**********************************************************
/* Additional 2.0 methods for appending/writing contents
/**********************************************************
*/
@Override
public int appendQuotedUTF8(byte[] buffer, int offset) {
byte[] result = _quotedUTF8Ref;
if (result == null) {
result = BufferRecyclers.quoteAsJsonUTF8(_value);
_quotedUTF8Ref = result;
}
final int length = result.length;
if ((offset + length) > buffer.length) {
return -1;
}
System.arraycopy(result, 0, buffer, offset, length);
return length;
}
@Override
public int appendQuoted(char[] buffer, int offset) {
char[] result = _quotedChars;
if (result == null) {
result = BufferRecyclers.quoteAsJsonText(_value);
_quotedChars = result;
}
final int length = result.length;
if ((offset + length) > buffer.length) {
return -1;
}
System.arraycopy(result, 0, buffer, offset, length);
return length;
}
@Override
public int appendUnquotedUTF8(byte[] buffer, int offset) {
byte[] result = _unquotedUTF8Ref;
if (result == null) {
result = BufferRecyclers.encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
final int length = result.length;
if ((offset + length) > buffer.length) {
return -1;
}
System.arraycopy(result, 0, buffer, offset, length);
return length;
}
@Override
public int appendUnquoted(char[] buffer, int offset) {
String str = _value;
final int length = str.length();
if ((offset + length) > buffer.length) {
return -1;
}
str.getChars(0, length, buffer, offset);
return length;
}
@Override
public int writeQuotedUTF8(OutputStream out) throws IOException {
byte[] result = _quotedUTF8Ref;
if (result == null) {
result = BufferRecyclers.quoteAsJsonUTF8(_value);
_quotedUTF8Ref = result;
}
final int length = result.length;
out.write(result, 0, length);
return length;
}
@Override
public int writeUnquotedUTF8(OutputStream out) throws IOException {
byte[] result = _unquotedUTF8Ref;
if (result == null) {
result = BufferRecyclers.encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
final int length = result.length;
out.write(result, 0, length);
return length;
}
@Override
public int putQuotedUTF8(ByteBuffer buffer) {
byte[] result = _quotedUTF8Ref;
if (result == null) {
result = BufferRecyclers.quoteAsJsonUTF8(_value);
_quotedUTF8Ref = result;
}
final int length = result.length;
if (length > buffer.remaining()) {
return -1;
}
buffer.put(result, 0, length);
return length;
}
@Override
public int putUnquotedUTF8(ByteBuffer buffer) {
byte[] result = _unquotedUTF8Ref;
if (result == null) {
result = BufferRecyclers.encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
final int length = result.length;
if (length > buffer.remaining()) {
return -1;
}
buffer.put(result, 0, length);
return length;
}
/*
/**********************************************************
/* 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);
}
}