/***********************************************************************************************************************
*
* 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.nephele.rpc;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
* This class implements a {@link Serializer} for the {@link Collection} objects. The implementation extends the
* built-in kryo collection serializer such that certain collections which do not have default constructor can also be
* serialized.
* <p>
* This class is not thread-safe.
*/
@SuppressWarnings("rawtypes")
final class CollectionSerializer extends Serializer<Collection> {
/**
* The built-in kryo serializer for collections with non-arg constructors.
*/
private final com.esotericsoftware.kryo.serializers.CollectionSerializer defaultSerializer;
/**
* Initializes CollectionSerializer.
*/
CollectionSerializer() {
this.defaultSerializer = new com.esotericsoftware.kryo.serializers.CollectionSerializer();
}
/**
* {@inheritDoc}
*/
@Override
public Collection read(final Kryo kryo, final Input input, final Class<Collection> type) {
if (hasNonArgConstructor(type))
return this.defaultSerializer.read(kryo, input, type);
final ArrayList al = kryo.readObject(input, ArrayList.class, this.defaultSerializer);
try {
final Constructor<Collection> constructor = type.getDeclaredConstructor(List.class);
constructor.setAccessible(true);
return constructor.newInstance(al);
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
/**
* {@inheritDoc}
*/
@Override
public void write(final Kryo kryo, final Output output, final Collection object) {
if (hasNonArgConstructor(object.getClass()))
this.defaultSerializer.write(kryo, output, object);
else {
@SuppressWarnings("unchecked")
final ArrayList<Object> al = new ArrayList<Object>(object);
kryo.writeObject(output, al, this.defaultSerializer);
}
}
/**
* Checks if the given class has a default constructor (i.e. a constructor with no arguments).
*
* @param class1
* the class to be checked
* @return <code>true</code> if the given class has a default constructor, <code>false</code> otherwise
*/
@SuppressWarnings("unchecked")
private static boolean hasNonArgConstructor(final Class<? extends Collection> class1) {
try {
final Constructor<Collection> constructor = (Constructor<Collection>) class1.getConstructor();
if (constructor != null)
return true;
} catch (final Exception e) {
}
return false;
}
}