/* * Copyright 2013 MovingBlocks * * 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.terasology.persistence.typeHandling; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.persistence.serializers.DeserializeFieldCheck; import org.terasology.reflection.metadata.ClassMetadata; import org.terasology.reflection.metadata.FieldMetadata; import java.util.Map; /** * A serializer provides low-level serialization support for a type, using a mapping of type handlers for each field of that type. * */ public class Serializer { private static final Logger logger = LoggerFactory.getLogger(Serializer.class); private ClassMetadata<?, ?> classMetadata; private Map<FieldMetadata<?, ?>, TypeHandler> fieldHandlers; public Serializer(ClassMetadata<?, ?> classMetadata, Map<FieldMetadata<?, ?>, TypeHandler> fieldHandlers) { this.fieldHandlers = fieldHandlers; this.classMetadata = classMetadata; } /** * @param field The metadata for a field of the type handled by this serializer. * @return The TypeHandler for the given field */ public TypeHandler<?> getHandlerFor(FieldMetadata<?, ?> field) { return fieldHandlers.get(field); } /** * Serializes a field of a provided container * * @param field The metadata for the field to serialize * @param container The object containing the field * @param context The current serialization context * @return The serialized value of the field */ @SuppressWarnings("unchecked") public PersistedData serialize(FieldMetadata<?, ?> field, Object container, SerializationContext context) { Object rawValue = field.getValue(container); if (rawValue != null) { TypeHandler handler = getHandlerFor(field); if (handler != null) { return handler.serialize(rawValue, context); } } return context.createNull(); } /** * Serializes the given value, that was originally obtained from the given field. * <br><br> * This is provided for performance, to avoid obtaining the same value twice. * * @param rawValue The value to serialize * @return The serialized value */ @SuppressWarnings("unchecked") public PersistedData serializeValue(FieldMetadata<?, ?> fieldMetadata, Object rawValue, SerializationContext context) { return fieldHandlers.get(fieldMetadata).serialize(rawValue, context); } /** * Deserializes a value onto an object * * @param target The object to deserialize the field onto * @param fieldMetadata The metadata of the field * @param data The serialized value of the field * @param context The deserialization context */ public void deserializeOnto(Object target, FieldMetadata<?, ?> fieldMetadata, PersistedData data, DeserializationContext context) { TypeHandler<?> handler = getHandlerFor(fieldMetadata); if (handler == null) { logger.error("No type handler for type {} used by {}::{}", fieldMetadata.getType(), target.getClass(), fieldMetadata); } else { try { Object deserializedValue = handler.deserialize(data, context); fieldMetadata.setValue(target, deserializedValue); } catch (DeserializationException e) { logger.error("Unable to deserialize field '{}' from '{}'", fieldMetadata.getName(), data.toString(), e); } } } /** * Deserializes a Collection of name-values onto an object * * @param target The object to deserialize onto * @param values The collection of values to apply to the object * @param context The deserialization context */ public void deserializeOnto(Object target, PersistedDataMap values, DeserializationContext context) { deserializeOnto(target, values, DeserializeFieldCheck.NullCheck.newInstance(), context); } /** * Deserializes a Collection of name-values onto an object * * @param target The object to deserialize onto * @param values The collection of values to apply to the object * @param check A check to filter which fields to deserialize */ public void deserializeOnto(Object target, PersistedDataMap values, DeserializeFieldCheck check, DeserializationContext context) { for (Map.Entry<String, PersistedData> field : values.entrySet()) { FieldMetadata<?, ?> fieldInfo = classMetadata.getField(field.getKey()); if (fieldInfo != null && check.shouldDeserialize(classMetadata, fieldInfo)) { deserializeOnto(target, fieldInfo, field.getValue(), context); } else if (fieldInfo == null) { logger.warn("Cannot deserialize unknown field '{}' onto '{}'", field.getKey(), classMetadata.getUri()); } } } /** * Deserializes a Collection of name-values onto an object * * @param target The object to deserialize onto * @param values The collection of values to apply to the object */ public void deserializeOnto(Object target, Map<FieldMetadata<?, ?>, PersistedData> values, DeserializationContext context) { deserializeOnto(target, values, context, DeserializeFieldCheck.NullCheck.newInstance()); } /** * Deserializes a Collection of name-values onto an object * * @param target The object to deserialize onto * @param values The collection of values to apply to the object * @param check A check to filter which fields to deserialize */ public void deserializeOnto(Object target, Map<FieldMetadata<?, ?>, PersistedData> values, DeserializationContext context, DeserializeFieldCheck check) { for (Map.Entry<FieldMetadata<?, ?>, PersistedData> field : values.entrySet()) { if (check.shouldDeserialize(classMetadata, field.getKey())) { deserializeOnto(target, field.getKey(), field.getValue(), context); } } } }