/**
* Copyright 2015 ArcBees 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 com.google.appengine.api.datastore;
import java.lang.reflect.Type;
import java.util.EnumSet;
import java.util.Set;
import com.arcbees.gaestudio.server.dto.mapper.EntityMapper;
import com.arcbees.gaestudio.server.util.JsonUtil;
import com.arcbees.gaestudio.shared.PropertyType;
import com.google.appengine.api.datastore.Entity.UnindexedValue;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import static com.arcbees.gaestudio.shared.PropertyName.GAE_PROPERTY_TYPE;
import static com.arcbees.gaestudio.shared.PropertyName.VALUE;
import static com.arcbees.gaestudio.shared.PropertyType.COLLECTION;
import static com.arcbees.gaestudio.shared.PropertyType.NULL;
public class PropertyValueAdapter implements JsonDeserializer<PropertyValue>, JsonSerializer<PropertyValue> {
private static final Set<PropertyType> EXCLUDED_METADATA_PROPERTY_TYPES = EnumSet.noneOf(PropertyType.class);
static {
EXCLUDED_METADATA_PROPERTY_TYPES.add(NULL);
EXCLUDED_METADATA_PROPERTY_TYPES.add(COLLECTION);
}
@Override
public JsonElement serialize(PropertyValue src, Type typeOfSrc, JsonSerializationContext context) {
Object value = src.getValue();
JsonElement serializedValue;
if (UnindexedValueAdapter.isUnindexedValue(value)) {
serializedValue = context.serialize(value, UnindexedValue.class);
} else {
PropertyType propertyType = getPropertyType(value);
Class<?> mappedClass = getMappedClass(propertyType);
serializedValue = context.serialize(value, mappedClass);
if (!EXCLUDED_METADATA_PROPERTY_TYPES.contains(propertyType)) {
serializedValue = appendPropertyType(serializedValue, propertyType.getRepresentation());
}
}
return serializedValue;
}
@Override
public PropertyValue deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Object value;
if (UnindexedValueAdapter.isUnindexedValue(json)) {
value = context.deserialize(json, UnindexedValue.class);
} else {
PropertyType propertyType = extractPropertyType(json);
Class<?> mappedClass = getMappedClass(propertyType);
if (JsonUtil.hasEmbedValue(json)) {
json = json.getAsJsonObject().get(VALUE);
}
value = context.deserialize(json, mappedClass);
value = cleanupValue(value, propertyType);
}
return new PropertyValue(value);
}
private PropertyType getPropertyType(Object value) {
if (value instanceof UnindexedValue) {
value = ((UnindexedValue) value).getValue();
}
return EntityMapper.getPropertyType(value);
}
private JsonElement appendPropertyType(JsonElement serializedValue, PropertyType propertyType) {
JsonObject wrapper;
if (JsonUtil.hasEmbedValue(serializedValue)) {
wrapper = serializedValue.getAsJsonObject();
} else {
wrapper = new JsonObject();
wrapper.add(VALUE, serializedValue);
}
wrapper.addProperty(GAE_PROPERTY_TYPE, propertyType.name());
return wrapper;
}
private Object cleanupValue(Object value, PropertyType propertyType) {
if (propertyType == PropertyType.STRING && value instanceof String) {
String string = (String) value;
if (string.length() > DataTypeUtils.MAX_STRING_PROPERTY_LENGTH) {
value = new Text(string);
}
}
return value;
}
private PropertyType extractPropertyType(JsonElement jsonElement) {
PropertyType propertyType = PropertyType.NULL;
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (jsonObject.has(GAE_PROPERTY_TYPE)) {
String propertyTypeName = jsonObject.get(GAE_PROPERTY_TYPE).getAsString();
propertyType = PropertyType.valueOf(propertyTypeName);
}
} else if (jsonElement.isJsonArray()) {
propertyType = COLLECTION;
}
return propertyType;
}
private Class<?> getMappedClass(PropertyType propertyType) {
Class<?> mappedClass;
try {
mappedClass = Class.forName(propertyType.getMappedClass());
} catch (ClassNotFoundException e) {
mappedClass = Object.class;
}
return mappedClass;
}
}