/***********************************************************************************************************************
 *
 * Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
 *
 * 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 eu.stratosphere.api.java.typeutils.runtime;

import java.io.IOException;

import org.apache.avro.reflect.ReflectDatumReader;
import org.apache.avro.reflect.ReflectDatumWriter;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.serializers.FieldSerializer;

import eu.stratosphere.api.common.typeutils.TypeSerializer;
import eu.stratosphere.core.memory.DataInputView;
import eu.stratosphere.core.memory.DataOutputView;
import eu.stratosphere.util.InstantiationUtil;


/**
 * General purpose serialization using Apache Avro's Reflect-serializers.
 * For deep object copies, this class is using Kryo.
 *
 * @param <T>
 */
public class AvroSerializer<T> extends TypeSerializer<T> {

	private static final long serialVersionUID = 1L;
	
	private transient ReflectDatumWriter<T> writer;
	private transient ReflectDatumReader<T> reader;
	
	private transient DataOutputEncoder encoder = new DataOutputEncoder();
	private transient DataInputDecoder decoder = new DataInputDecoder();
	
	private transient Kryo kryo;
	
	private transient FieldSerializer<T> serializer;

	private final Class<T> type;
	
	// --------------------------------------------------------------------------------------------
	
	public AvroSerializer(Class<T> type) {
		this.type = type;
	}

	// --------------------------------------------------------------------------------------------
	
	@Override
	public boolean isImmutableType() {
		return false;
	}

	@Override
	public boolean isStateful() {
		return true;
	}
	
	@Override
	public T createInstance() {
		return InstantiationUtil.instantiate(type, Object.class);
	}

	@Override
	public T copy(T from, T reuse) {
		reuse = kryo.copy(from);
		return reuse;
	}

	@Override
	public int getLength() {
		return -1;
	}

	@Override
	public void serialize(T value, DataOutputView target) throws IOException {
		checkAvroInitialized();
		this.encoder.setOut(target);
		this.writer.write(value, this.encoder);
	}

	@Override
	public T deserialize(T reuse, DataInputView source) throws IOException {
		checkAvroInitialized();
		this.decoder.setIn(source);
		return this.reader.read(reuse, this.decoder);
	}

	@Override
	public void copy(DataInputView source, DataOutputView target) throws IOException {
		throw new UnsupportedOperationException();
	}
	
	
	private final void checkAvroInitialized() {
		if (this.reader == null) {
			this.reader = new ReflectDatumReader<T>(type);
			this.writer = new ReflectDatumWriter<T>(type);
			this.encoder = new DataOutputEncoder();
			this.decoder = new DataInputDecoder();
		}
	}
	
	private final void checkKryoInitialized() {
		if (this.kryo == null) {
			this.kryo = new Kryo();
			this.kryo.setAsmEnabled(true);
			this.kryo.register(type);
			this.serializer = new FieldSerializer<T>(kryo, type);
		}
	}
	
	// --------------------------------------------------------------------------------------------
	// serialization
	// --------------------------------------------------------------------------------------------
	
	private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
		// read basic object and the type
		s.defaultReadObject();
		
		this.reader = null;
		this.writer = null;
		this.encoder = null;
		this.decoder = null;
		this.kryo = null;
	}
}

@@ -1131,25 +1131,8 @@
 ryo.
-serializers.Field
 Seri
@@ -1497,16 +1497,37 @@
 aram %3CT%3E
+ The type serialized.
 %0A */%0Apub
@@ -1631,24 +1631,56 @@
 UID = 1L;%0A%09%0A
+%09private final Class%3CT%3E type;%0A%09%0A
 %09private tra
@@ -1815,34 +1815,8 @@
 oder
- = new DataOutputEncoder()
 ;%0A%09p
@@ -1860,33 +1860,8 @@
 oder
- = new DataInputDecoder()
 ;%0A%09%0A
@@ -1911,21 +1911,16 @@
 ansient 
-Field
 Serializ
@@ -1937,16 +1937,17 @@
 alizer;%0A
+%09
 %0A%09privat
@@ -1948,34 +1948,43 @@
 private 
-final Class%3CT%3E typ
+transient T deepCopyInstanc
 e;%0A%09%0A%09//
@@ -2526,26 +2526,69 @@
 %7B%0A%09%09
-reuse = kryo.copy(
+checkKryoInitialized();%0A%09%09reuse = serializer.copy(this.kryo, 
 from
@@ -3148,48 +3148,325 @@
 %7B%0A%09%09
-throw new UnsupportedOperationException(
+checkAvroInitialized();%0A%09%09%0A%09%09if (this.deepCopyInstance == null) %7B%0A%09%09%09this.deepCopyInstance = InstantiationUtil.instantiate(type, Object.class);%0A%09%09%7D%0A%09%09%0A%09%09this.decoder.setIn(source);%0A%09%09this.encoder.setOut(target);%0A%09%09%0A%09%09T tmp = this.reader.read(this.deepCopyInstance, this.decoder);%0A%09%09this.writer.write(tmp, this.encoder
 );%0A%09
@@ -3739,16 +3739,48 @@
 %09%7D%0A%09%7D%0A%09%0A
+%09@SuppressWarnings(%22unchecked%22)%0A
 %09private
@@ -3958,37 +3958,37 @@
 r = 
-new FieldSerializer%3CT%3E(kryo, 
+this.kryo.getSerializer(this.
 type

Add object copying code to AvroSerializer