/*
* Copyright 2016 requery.io
*
* 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 io.requery.android;
import android.os.Parcel;
import android.os.Parcelable;
import io.requery.meta.Attribute;
import io.requery.meta.Type;
import io.requery.proxy.EntityProxy;
import io.requery.proxy.PropertyState;
/**
* Handler for Android's Parcelable objects. Serializes field types that are handled by
* {@link Parcel#readValue(ClassLoader)} and {@link Parcel#writeValue(Object)}. If using a field
* that doesn't support those you must implement the parcelable interface in the object.
*
* @author Nikhil Purushe
*/
public class EntityParceler<T> {
private final Type<T> type;
public EntityParceler(Type<T> type) {
this.type = type;
}
public T readFromParcel(Parcel in) {
T entity = type.getFactory().get();
EntityProxy<T> proxy = type.getProxyProvider().apply(entity);
for (Attribute<T, ?> attribute : type.getAttributes()) {
if (attribute.isAssociation()) {
continue;
}
Class<?> typeClass = attribute.getClassType();
Object value = null;
if (typeClass.isEnum()) {
String name = (String) in.readValue(getClass().getClassLoader());
if (name == null) {
value = null;
} else {
@SuppressWarnings("unchecked")
Class<? extends Enum> enumClass = (Class<? extends Enum>) typeClass;
value = Enum.valueOf(enumClass, name);
}
} else if (typeClass.isArray()) {
int length = in.readInt();
if (length >= 0) {
try {
Parcelable.Creator creator = (Parcelable.Creator<?>)
typeClass.getField("CREATOR").get(null);
Object[] array = creator.newArray(length);
in.readTypedArray(array, creator);
value = array;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} else {
value = in.readValue(getClass().getClassLoader());
}
PropertyState state = PropertyState.LOADED;
if (!type.isStateless()) {
state = PropertyState.valueOf(in.readString());
}
proxy.setObject(attribute, value, state);
}
return entity;
}
public void writeToParcel(T entity, Parcel out) {
EntityProxy<T> proxy = type.getProxyProvider().apply(entity);
for (Attribute<T, ?> attribute : type.getAttributes()) {
if (attribute.isAssociation()) {
continue;
}
Object value = proxy.get(attribute, false);
Class<?> typeClass = attribute.getClassType();
if (typeClass.isArray()) {
Parcelable[] array = (Parcelable[]) value;
if (array == null) {
out.writeInt(-1);
} else {
out.writeInt(array.length);
out.writeTypedArray(array, 0);
}
} else {
if (typeClass.isEnum()) {
if (value != null) {
value = value.toString();
}
}
out.writeValue(value);
}
if (!type.isStateless()) {
PropertyState state = proxy.getState(attribute);
out.writeString(state.toString());
}
}
}
}