/*
* Copyright Terracotta, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ehcache.impl.serialization;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.ehcache.spi.serialization.Serializer;
import org.ehcache.spi.serialization.SerializerException;
Default Serializer
for String
type. Simply writes the string bytes in modified UTF-8 to a byte buffer. /**
* Default {@link Serializer} for {@code String} type. Simply writes the string bytes in modified UTF-8
* to a byte buffer.
*/
public class StringSerializer implements Serializer<String> {
No arg constructor
/**
* No arg constructor
*/
public StringSerializer() {
}
Constructor to enable this serializer as a transient one.
Parameter is ignored as String
is a base java type.
Params: - classLoader – the classloader to use
See Also:
/**
* Constructor to enable this serializer as a transient one.
* <p>
* Parameter is ignored as {@link String} is a base java type.
*
* @param classLoader the classloader to use
*
* @see Serializer
*/
public StringSerializer(ClassLoader classLoader) {
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
@Override
public ByteBuffer serialize(String object) {
int length = object.length();
try(ByteArrayOutputStream bout = new ByteArrayOutputStream(length)) {
int i = 0;
for (; i < length; i++) {
char c = object.charAt(i);
if (c == 0x0000 || c > 0x007f) {
break;
}
bout.write(c);
}
for (; i < length; i++) {
char c = object.charAt(i);
if (c == 0x0000) {
bout.write(0xc0);
bout.write(0x80);
} else if (c < 0x0080) {
bout.write(c);
} else if (c < 0x800) {
bout.write(0xc0 | ((c >>> 6) & 0x1f));
bout.write(0x80 | (c & 0x3f));
} else {
bout.write(0xe0 | ((c >>> 12) & 0x1f));
bout.write(0x80 | ((c >>> 6) & 0x3f));
bout.write(0x80 | (c & 0x3f));
}
}
return ByteBuffer.wrap(bout.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
@Override
public String read(ByteBuffer binary) throws ClassNotFoundException {
StringBuilder sb = new StringBuilder(binary.remaining());
int i = binary.position();
int end = binary.limit();
for (; i < end; i++) {
byte a = binary.get(i);
if (((a & 0x80) != 0)) break;
sb.append((char) a);
}
for (; i < end; i++) {
byte a = binary.get(i);
if ((a & 0x80) == 0) {
sb.append((char) a);
} else if ((a & 0xe0) == 0xc0) {
sb.append((char) (((a & 0x1f) << 6) | ((binary.get(++i) & 0x3f))));
} else if ((a & 0xf0) == 0xe0) {
sb.append((char) (((a & 0x0f) << 12) | ((binary.get(++i) & 0x3f) << 6) | (binary.get(++i) & 0x3f)));
} else {
//these remaining stanzas are for compatibility with the previous regular UTF-8 codec
int codepoint;
if ((a & 0xf8) == 0xf0) {
codepoint = ((a & 0x7) << 18) | ((binary.get(++i) & 0x3f) << 12) | ((binary.get(++i) & 0x3f) << 6) | ((binary.get(++i) & 0x3f));
} else if ((a & 0xfc) == 0xf8) {
codepoint = ((a & 0x3) << 24) | ((binary.get(++i) & 0x3f) << 18) | ((binary.get(++i) & 0x3f) << 12) | ((binary.get(++i) & 0x3f) << 6) | ((binary.get(++i) & 0x3f));
} else if ((a & 0xfe) == 0xfc) {
codepoint = ((a & 0x1) << 30) | ((binary.get(++i) & 0x3f) << 24) | ((binary.get(++i) & 0x3f) << 18) | ((binary.get(++i) & 0x3f) << 12) | ((binary.get(++i) & 0x3f) << 6) | ((binary.get(++i) & 0x3f));
} else {
throw new SerializerException("Unexpected encoding");
}
sb.appendCodePoint(codepoint);
}
}
return sb.toString();
}
{@inheritDoc}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(String object, ByteBuffer binary) throws ClassNotFoundException {
if (binary.remaining() < object.length()) {
return false;
} else {
int bEnd = binary.limit();
int bi = binary.position();
int sLength = object.length();
int si = 0;
for (; bi < bEnd && si < sLength; bi++, si++) {
byte a = binary.get(bi);
if (((a & 0x80) != 0)) break;
if (object.charAt(si) != (char) a) {
return false;
}
}
for (; bi < bEnd && si < sLength; bi++, si++) {
byte a = binary.get(bi);
if ((a & 0x80) == 0) {
if (object.charAt(si) != (char) a) {
return false;
}
} else if ((a & 0xe0) == 0xc0) {
if (object.charAt(si) != (char) (((a & 0x1f) << 6) | ((binary.get(++bi) & 0x3f)))) {
return false;
}
} else if ((a & 0xf0) == 0xe0) {
if (object.charAt(si) != (char) (((a & 0x0f) << 12) | ((binary.get(++bi) & 0x3f) << 6) | (binary.get(++bi) & 0x3f))) {
return false;
}
} else {
//these remaining stanzas are for compatibility with the previous regular UTF-8 codec
int codepoint;
if ((a & 0xf8) == 0xf0) {
codepoint = ((a & 0x7) << 18) | ((binary.get(++bi) & 0x3f) << 12) | ((binary.get(++bi) & 0x3f) << 6) | ((binary.get(++bi) & 0x3f));
} else if ((a & 0xfc) == 0xf8) {
codepoint = ((a & 0x3) << 24) | ((binary.get(++bi) & 0x3f) << 18) | ((binary.get(++bi) & 0x3f) << 12) | ((binary.get(++bi) & 0x3f) << 6) | ((binary.get(++bi) & 0x3f));
} else if ((a & 0xfe) == 0xfc) {
codepoint = ((a & 0x1) << 30) | ((binary.get(++bi) & 0x3f) << 24) | ((binary.get(++bi) & 0x3f) << 18) | ((binary.get(++bi) & 0x3f) << 12) | ((binary.get(++bi) & 0x3f) << 6) | ((binary.get(++bi) & 0x3f));
} else {
throw new SerializerException("Unrecognized encoding");
}
char[] chars = Character.toChars(codepoint);
if (si + 1 == sLength || object.charAt(si) != chars[0] || object.charAt(++si) != chars[1]) {
return false;
}
}
}
return bi == bEnd && si == sLength;
}
}
}