Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enumeration Serialization #6

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ private static void writeField(SafeParcelable object, Parcel parcel, Field field
case String:
SafeParcelWriter.write(parcel, fieldId, (String) field.get(object), mayNull);
break;
case Enum:
SafeParcelWriter.write(parcel, fieldId, field, (Enum)field.get(object), mayNull);
break;
}
field.setAccessible(acc);
}
Expand Down Expand Up @@ -379,15 +382,51 @@ private static void readField(SafeParcelable object, Parcel parcel, Field field,
break;
case Byte:
break;
case Enum:
readEnum(object, parcel, field, header);
break;
default:
throw new IllegalStateException("Unexpected value: " + SafeParcelType.fromField(field));
}
field.setAccessible(acc);
}

private static final Map<Class<?>, Map<Integer, Enum<?>>> statefulOrdinalsMap = new HashMap<>();

private static void readEnum(SafeParcelable object, Parcel parcel, Field field, int header) throws IllegalAccessException {

Map<Integer, Enum<?>> statefulOrdinals = null;
synchronized (SafeParcelUtil.class) {
statefulOrdinals = statefulOrdinalsMap.get(field.getType());
if (statefulOrdinals == null) {
statefulOrdinals = new HashMap<>();
for (Object enumObject : field.getType().getEnumConstants()) {
Enum enumConstant = (Enum) enumObject;
Field declaredField = null;
try {
declaredField = field.getType().getDeclaredField(enumConstant.name());
} catch (NoSuchFieldException e) {
throw new IllegalStateException("Invalid enum value: " + SafeParcelType.fromField(field));
}
SafeParcelable.Field annotation = declaredField.getAnnotation(SafeParcelable.Field.class);
if (annotation != null) {
statefulOrdinals.put(annotation.value(), enumConstant);
} else {
throw new IllegalStateException("Invalid enum value (no annotation): " + SafeParcelType.fromField(field));
}
}
statefulOrdinalsMap.put(field.getType(), statefulOrdinals);
}
}

int statefulOrdinal = SafeParcelReader.readInt(parcel, header);
Enum enumConstant = statefulOrdinals.get(statefulOrdinal);
field.set(object, enumConstant);
}

private enum SafeParcelType {
Parcelable, Binder, StringList, List, Bundle, ParcelableArray, StringArray, ByteArray,
Interface, IntArray, Integer, Long, Boolean, Float, Double, String, Map, Byte;
Interface, IntArray, Integer, Long, Boolean, Float, Double, String, Map, Byte, Enum;

public static SafeParcelType fromField(Field field) {
Class clazz = field.getType();
Expand Down Expand Up @@ -428,6 +467,8 @@ public static SafeParcelType fromField(Field field) {
return Byte;
if (clazz == java.lang.String.class)
return String;
if (Enum.class.isAssignableFrom(clazz))
return Enum;
throw new RuntimeException("Type is not yet usable with SafeParcelUtil: " + clazz);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.os.Parcel;
import android.os.Parcelable;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -279,4 +280,27 @@ public static void write(Parcel parcel, int fieldId, IBinder val, boolean mayNul
}
}

public static void write(Parcel parcel, int fieldId, Field field, Enum val, boolean mayNull) {
if (val == null) {
if (mayNull) {
writeHeader(parcel, fieldId, 0);
}
} else {
int start = writeObjectHeader(parcel, fieldId);
Field enumConstantField = null;
try {
enumConstantField = field.getType().getDeclaredField(val.name());
} catch (NoSuchFieldException e) {
throw new RuntimeException("Invalid enum: field is absent");
}
SafeParcelable.Field annotation = enumConstantField.getAnnotation(SafeParcelable.Field.class);
if (annotation != null) {
parcel.writeInt(annotation.value());
} else {
throw new RuntimeException("Invalid enum: Annotation is missing");
}
finishObjectHeader(parcel, start);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public void foo() {
foo1.barList.add(foo1.bar);
foo1.barArray = new Bar[]{foo1.bar};
foo1.intList.add(2);
foo1.enumType = Type.OFFLINE;
Foo foo2 = remarshal(foo1, Foo.CREATOR);
assertEquals(foo1, foo2);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class Foo extends AutoSafeParcelable {
public Bar[] barArray = new Bar[0];
@Field(9)
public List<Integer> intList = new ArrayList<>();
@Field(10)
public Type enumType = Type.OFFLINE;

private Foo() {
}
Expand All @@ -57,6 +59,7 @@ public String toString() {
", barList=" + barList +
", barArray=" + Arrays.toString(barArray) +
", intList=" + intList +
", enumType=" + enumType +
'}';
}

Expand All @@ -73,12 +76,13 @@ public boolean equals(Object o) {
Objects.equals(bar, foo.bar) &&
Objects.equals(barList, foo.barList) &&
Arrays.equals(barArray, foo.barArray) &&
Objects.equals(intList, foo.intList);
Objects.equals(intList, foo.intList) &&
Objects.equals(enumType, foo.enumType);
}

@Override
public int hashCode() {
int result = Objects.hash(versionCode, intPrivate, string, stringList, stringStringMap, bar, barList, intList);
int result = Objects.hash(versionCode, intPrivate, string, stringList, stringStringMap, bar, barList, intList, enumType);
result = 31 * result + Arrays.hashCode(barArray);
return result;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2019, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/

package org.microg.safeparcel.test.auto;

import org.microg.safeparcel.SafeParcelable;

public enum Type {
@SafeParcelable.Field(1)
ONLINE,
@SafeParcelable.Field(2)
OFFLINE
}