Skip to content

Commit 17a0ae2

Browse files
committed
Handle a generic Serializable or Parcelable properly, see #24
1 parent 34ee48f commit 17a0ae2

File tree

6 files changed

+117
-13
lines changed

6 files changed

+117
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## 1.1.1
22

33
* Add a Proguard rule to keep the class name if the class contains a `State` or `StateReflection annoation`, see #23
4+
* Handle a generic `Serializable` or `Parcelable` properly, see #24
45

56
## 1.1.0 (2017-06-05)
67

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.evernote.android.test.data;
2+
3+
import java.io.Serializable;
4+
5+
/**
6+
* @author rwondratschek
7+
*/
8+
public class GenericSerializable<T> implements Serializable {
9+
10+
private T mValue;
11+
12+
public T getValue() {
13+
return mValue;
14+
}
15+
16+
public void setValue(T value) {
17+
mValue = value;
18+
}
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.evernote.android.test.data;
2+
3+
import com.evernote.android.state.State;
4+
5+
/**
6+
* @author rwondratschek
7+
*/
8+
public class TestJavaGenericSerializable {
9+
10+
@State
11+
private GenericSerializable<String> mGenericSerializable;
12+
13+
public GenericSerializable<String> getGenericSerializable() {
14+
return mGenericSerializable;
15+
}
16+
17+
public void setGenericSerializable(GenericSerializable<String> genericSerializable) {
18+
mGenericSerializable = genericSerializable;
19+
}
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.evernote.android.state.test
2+
3+
import com.evernote.android.state.State
4+
import com.evernote.android.test.data.GenericSerializable
5+
6+
/**
7+
* @author rwondratschek
8+
*/
9+
class TestKotlinGenericSerializable {
10+
11+
@State
12+
var genericSerializable: GenericSerializable<String>? = null
13+
}

demo/src/test/kotlin/com/evernote/android/state/test/TestKotlinBundling.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ package com.evernote.android.state.test
1212

1313
import android.os.Bundle
1414
import com.evernote.android.state.StateSaver
15+
import com.evernote.android.test.data.GenericSerializable
16+
import com.evernote.android.test.data.TestJavaGenericSerializable
1517
import org.assertj.core.api.Assertions.assertThat
1618
import org.junit.FixMethodOrder
1719
import org.junit.Test
@@ -121,4 +123,37 @@ class TestKotlinBundling {
121123
assertThat(kotlinBoolean.test1).isTrue()
122124
assertThat(kotlinBoolean.isTest2).isTrue()
123125
}
126+
127+
@Test
128+
fun testGenericSerializable() {
129+
val javaGenericSerializable = TestJavaGenericSerializable()
130+
val kotlinGenericSerializable = TestKotlinGenericSerializable()
131+
assertThat(javaGenericSerializable.genericSerializable).isNull()
132+
assertThat(kotlinGenericSerializable.genericSerializable).isNull()
133+
134+
val bundle = Bundle()
135+
StateSaver.saveInstanceState(javaGenericSerializable, bundle)
136+
StateSaver.saveInstanceState(kotlinGenericSerializable, bundle)
137+
138+
javaGenericSerializable.genericSerializable = GenericSerializable()
139+
kotlinGenericSerializable.genericSerializable = GenericSerializable()
140+
141+
StateSaver.restoreInstanceState(javaGenericSerializable, bundle)
142+
StateSaver.restoreInstanceState(kotlinGenericSerializable, bundle)
143+
assertThat(javaGenericSerializable.genericSerializable).isNull()
144+
assertThat(kotlinGenericSerializable.genericSerializable).isNull()
145+
146+
javaGenericSerializable.genericSerializable = GenericSerializable()
147+
kotlinGenericSerializable.genericSerializable = GenericSerializable()
148+
StateSaver.saveInstanceState(javaGenericSerializable, bundle)
149+
StateSaver.saveInstanceState(kotlinGenericSerializable, bundle)
150+
151+
javaGenericSerializable.genericSerializable = null
152+
kotlinGenericSerializable.genericSerializable = null
153+
154+
StateSaver.restoreInstanceState(javaGenericSerializable, bundle)
155+
StateSaver.restoreInstanceState(kotlinGenericSerializable, bundle)
156+
assertThat(javaGenericSerializable.genericSerializable as Any).isNotNull()
157+
assertThat(kotlinGenericSerializable.genericSerializable as Any).isNotNull()
158+
}
124159
}

processor/src/main/java/com/evernote/android/state/StateProcessor.java

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ public int compare(Element o1, Element o2) {
121121
private static final String PARCELABLE_CLASS_NAME = Parcelable.class.getName();
122122
private static final String SERIALIZABLE_CLASS_NAME = Serializable.class.getName();
123123

124+
private static final Set<String> GENERIC_SUPER_TYPES = Collections.unmodifiableSet(new HashSet<String>() {{
125+
add(PARCELABLE_CLASS_NAME);
126+
add(SERIALIZABLE_CLASS_NAME);
127+
}});
128+
124129
private static final Set<String> IGNORED_TYPE_DECLARATIONS = Collections.unmodifiableSet(new HashSet<String>() {{
125130
add(Bundle.class.getName());
126131
add(String.class.getName());
@@ -785,15 +790,23 @@ private TypeMirror getInsertedType(Element field, @SuppressWarnings("SameParamet
785790
}
786791

787792
private TypeMirror getInsertedType(TypeMirror fieldType, boolean checkIgnoredTypes) {
793+
TypeElement classElement = mElementUtils.getTypeElement(eraseGenericIfNecessary(fieldType).toString());
794+
List<? extends TypeMirror> superTypes = classElement == null ? null : mTypeUtils.directSupertypes(classElement.asType());
795+
788796
if (fieldType instanceof DeclaredType) {
789-
// generic type, return the generic value
790797
List<? extends TypeMirror> typeArguments = ((DeclaredType) fieldType).getTypeArguments();
791798
if (typeArguments != null && !typeArguments.isEmpty()) {
799+
// generic type, return the generic value
800+
801+
if (superTypes != null && isSuperType(superTypes, GENERIC_SUPER_TYPES) && !fieldType.toString().startsWith(ArrayList.class.getName())) {
802+
// if this is generic Parcelable or Serializable, then use the type, ignore ArrayList, which also implements Serializable
803+
return fieldType;
804+
}
805+
792806
return getInsertedType(typeArguments.get(0), false);
793807
}
794808
}
795809

796-
TypeElement classElement = mElementUtils.getTypeElement(fieldType.toString());
797810
if (classElement == null || OBJECT_CLASS_NAME.equals(classElement.toString())) {
798811
return null;
799812
}
@@ -802,19 +815,13 @@ private TypeMirror getInsertedType(TypeMirror fieldType, boolean checkIgnoredTyp
802815
return null;
803816
}
804817

805-
List<? extends TypeMirror> typeMirrors = mTypeUtils.directSupertypes(classElement.asType());
806-
if (typeMirrors != null) {
807-
for (TypeMirror superType : typeMirrors) {
808-
String superTypeString = superType.toString();
809-
if (PARCELABLE_CLASS_NAME.equals(superTypeString)) {
810-
return fieldType;
811-
}
812-
if (SERIALIZABLE_CLASS_NAME.equals(superTypeString)) {
813-
return fieldType;
814-
}
818+
if (superTypes != null) {
819+
if (isSuperType(superTypes, GENERIC_SUPER_TYPES)) {
820+
// either instance of Serializable or Parcelable
821+
return fieldType;
815822
}
816823

817-
for (TypeMirror superType : typeMirrors) {
824+
for (TypeMirror superType : superTypes) {
818825
TypeMirror result = getInsertedType(eraseGenericIfNecessary(superType), checkIgnoredTypes);
819826
if (result != null) {
820827
// always return the passed in type and not any super type
@@ -825,6 +832,15 @@ private TypeMirror getInsertedType(TypeMirror fieldType, boolean checkIgnoredTyp
825832
return null;
826833
}
827834

835+
private boolean isSuperType(List<? extends TypeMirror> typeMirrors, Collection<String> superTypes) {
836+
for (TypeMirror superType : typeMirrors) {
837+
if (superTypes.contains(superType.toString())) {
838+
return true;
839+
}
840+
}
841+
return false;
842+
}
843+
828844
private String getLicenseHeader() throws IOException {
829845
if (mLicenseHeader == null) {
830846
synchronized (this) {

0 commit comments

Comments
 (0)