/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cassandra.io;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericArray;
import org.apache.avro.generic.GenericData;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.ipc.ByteBufferInputStream;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
import org.apache.avro.specific.SpecificRecord;
import org.apache.avro.util.Utf8;
import org.apache.cassandra.io.util.OutputBuffer;
/**
* Static serialization/deserialization utility functions, intended to eventually replace ICompactSerializers.
*/
public final class SerDeUtils
{
// unbuffered decoders
private final static DecoderFactory DIRECT_DECODERS = new DecoderFactory().configureDirectDecoder(true);
public static byte[] copy(ByteBuffer buff)
{
byte[] bytes = new byte[buff.remaining()];
buff.get(bytes);
buff.rewind();
return bytes;
}
/**
* Deserializes a single object based on the given Schema.
* @param writer writer's schema
* @param bytes Array to deserialize from
* @param ob An empty object to deserialize into (must not be null).
* @throws IOException
*/
public static <T extends SpecificRecord> T deserialize(Schema writer, ByteBuffer bytes, T ob) throws IOException
{
BinaryDecoder dec = DIRECT_DECODERS.createBinaryDecoder(bytes.array(),bytes.position()+bytes.arrayOffset(),bytes.remaining(), null);
SpecificDatumReader<T> reader = new SpecificDatumReader<T>(writer);
reader.setExpected(ob.getSchema());
return reader.read(ob, dec);
}
/**
* Serializes a single object.
* @param o Object to serialize
*/
public static <T extends SpecificRecord> ByteBuffer serialize(T o) throws IOException
{
OutputBuffer buff = new OutputBuffer();
BinaryEncoder enc = new BinaryEncoder(buff);
SpecificDatumWriter<T> writer = new SpecificDatumWriter<T>(o.getSchema());
writer.write(o, enc);
enc.flush();
return ByteBuffer.wrap(buff.asByteArray());
}
/**
* Deserializes a single object as stored along with its Schema by serialize(T). NB: See warnings on serialize(T).
* @param ob An empty object to deserialize into (must not be null).
* @param bytes Array to deserialize from
* @throws IOException
*/
public static <T extends SpecificRecord> T deserializeWithSchema(ByteBuffer bytes, T ob) throws IOException
{
BinaryDecoder dec = DIRECT_DECODERS.createBinaryDecoder(bytes.array(),bytes.position()+bytes.arrayOffset(), bytes.remaining(), null);
Schema writer = Schema.parse(dec.readString(new Utf8()).toString());
SpecificDatumReader<T> reader = new SpecificDatumReader<T>(writer);
reader.setExpected(ob.getSchema());
return reader.read(ob, dec);
}
/**
* Serializes a single object along with its Schema. NB: For performance critical areas, it is <b>much</b>
* more efficient to store the Schema independently.
* @param o Object to serialize
*/
public static <T extends SpecificRecord> ByteBuffer serializeWithSchema(T o) throws IOException
{
OutputBuffer buff = new OutputBuffer();
BinaryEncoder enc = new BinaryEncoder(buff);
enc.writeString(new Utf8(o.getSchema().toString()));
SpecificDatumWriter<T> writer = new SpecificDatumWriter<T>(o.getSchema());
writer.write(o, enc);
enc.flush();
return ByteBuffer.wrap(buff.asByteArray());
}
/**
* @return a DataInputStream wrapping the given buffer.
*/
public static DataInputStream createDataInputStream(ByteBuffer buff)
{
ByteBufferInputStream bbis = new ByteBufferInputStream(Collections.singletonList(buff));
return new DataInputStream(bbis);
}
/**
* Create a generic array of the given type and size. Mostly to minimize imports.
*/
public static <T> GenericArray<T> createArray(int size, Schema schema)
{
return new GenericData.Array<T>(size, Schema.createArray(schema));
}
}