From 91bfb8f36ebd7c6d431e2c4f93b3c8c25093914a Mon Sep 17 00:00:00 2001 From: Timur Valiulin Date: Mon, 14 Sep 2020 14:39:40 -0700 Subject: [PATCH 1/4] Enumeration serialization proposal --- .../org/microg/safeparcel/SafeParcelUtil.java | 45 ++++++++++++++++++- .../microg/safeparcel/SafeParcelWriter.java | 24 ++++++++++ .../safeparcel/test/auto/AutoTests.java | 1 + .../org/microg/safeparcel/test/auto/Foo.java | 8 +++- .../org/microg/safeparcel/test/auto/Type.java | 10 +++++ 5 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java diff --git a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java index 7295b2c..03ddd81 100644 --- a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java +++ b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java @@ -55,7 +55,7 @@ public static void writeObject(SafeParcelable object, Parcel parcel, int flags) try { writeField(object, parcel, field, flags); } catch (Exception e) { - Log.w(TAG, "Error writing field: " + e); + Log.w(TAG, "Error writing field: " + e, e); } } } @@ -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); } @@ -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, Map>> statefulOrdinalsMap = new HashMap<>(); + + private static synchronized void readEnum(SafeParcelable object, Parcel parcel, Field field, int header) throws IllegalAccessException { + + Map> 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(); @@ -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); } } diff --git a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelWriter.java b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelWriter.java index 02f5ac8..7c8b41f 100644 --- a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelWriter.java +++ b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelWriter.java @@ -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; @@ -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); + } + } + } diff --git a/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/AutoTests.java b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/AutoTests.java index 3af73ad..88034bd 100644 --- a/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/AutoTests.java +++ b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/AutoTests.java @@ -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); } diff --git a/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Foo.java b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Foo.java index f7f3967..7fdb64f 100644 --- a/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Foo.java +++ b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Foo.java @@ -33,6 +33,8 @@ class Foo extends AutoSafeParcelable { public Bar[] barArray = new Bar[0]; @Field(9) public List intList = new ArrayList<>(); + @Field(10) + public Type enumType = Type.OFFLINE; private Foo() { } @@ -57,6 +59,7 @@ public String toString() { ", barList=" + barList + ", barArray=" + Arrays.toString(barArray) + ", intList=" + intList + + ", enumType=" + enumType + '}'; } @@ -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; } diff --git a/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java new file mode 100644 index 0000000..6b065ff --- /dev/null +++ b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java @@ -0,0 +1,10 @@ +package org.microg.safeparcel.test.auto; + +import org.microg.safeparcel.SafeParcelable; + +public enum Type { + @SafeParcelable.Field(1) + ONLINE, + @SafeParcelable.Field(2) + OFFLINE +} From 608d2b783b512f0fca03f08b6ca35d3af6018851 Mon Sep 17 00:00:00 2001 From: Timur Valiulin Date: Mon, 14 Sep 2020 14:45:56 -0700 Subject: [PATCH 2/4] Undoing logging --- .../src/main/java/org/microg/safeparcel/SafeParcelUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java index 03ddd81..689fa59 100644 --- a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java +++ b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java @@ -55,7 +55,7 @@ public static void writeObject(SafeParcelable object, Parcel parcel, int flags) try { writeField(object, parcel, field, flags); } catch (Exception e) { - Log.w(TAG, "Error writing field: " + e, e); + Log.w(TAG, "Error writing field: " + e); } } } From 7284d0c283b4472aa4619c498ab7c96cec6571cd Mon Sep 17 00:00:00 2001 From: Timur Valiulin Date: Mon, 14 Sep 2020 14:47:46 -0700 Subject: [PATCH 3/4] Removing unnecessary synchronization --- .../src/main/java/org/microg/safeparcel/SafeParcelUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java index 689fa59..08a684e 100644 --- a/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java +++ b/safe-parcel/src/main/java/org/microg/safeparcel/SafeParcelUtil.java @@ -393,7 +393,7 @@ private static void readField(SafeParcelable object, Parcel parcel, Field field, private static final Map, Map>> statefulOrdinalsMap = new HashMap<>(); - private static synchronized void readEnum(SafeParcelable object, Parcel parcel, Field field, int header) throws IllegalAccessException { + private static void readEnum(SafeParcelable object, Parcel parcel, Field field, int header) throws IllegalAccessException { Map> statefulOrdinals = null; synchronized (SafeParcelUtil.class) { From 9d3814dc54cc03cc9bb2fa0f8df08db0787dc4e8 Mon Sep 17 00:00:00 2001 From: Timur Valiulin Date: Mon, 14 Sep 2020 21:13:26 -0700 Subject: [PATCH 4/4] Fixed copyright message --- .../src/test/java/org/microg/safeparcel/test/auto/Type.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java index 6b065ff..1ea5938 100644 --- a/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java +++ b/safe-parcel/src/test/java/org/microg/safeparcel/test/auto/Type.java @@ -1,3 +1,8 @@ +/* + * SPDX-FileCopyrightText: 2019, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + package org.microg.safeparcel.test.auto; import org.microg.safeparcel.SafeParcelable;