From ab770ed184b161096c83682a42de2a3e4afff75d Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Wed, 30 May 2018 11:00:56 -0700 Subject: [PATCH 01/18] Use implementation instead of compile in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04818ee..77138a4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Download the latest [library](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%2 ```groovy dependencies { - compile 'com.evernote:android-state:1.3.0' + implementation 'com.evernote:android-state:1.3.0' // Java only project annotationProcessor 'com.evernote:android-state-processor:1.3.0' From 91d511e7ce329b50600b41595d5e933b7769fffe Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 10 Jun 2018 11:40:46 -0700 Subject: [PATCH 02/18] Upgrade Gradle wrapper --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 54418 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 4e61e52..2848728 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ ext { } task wrapper(type: Wrapper) { - gradleVersion = '4.8-rc-2' + gradleVersion = '4.8' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1e713643223f69affdc73b4e99866c075e2715bf..1948b9074f1016d15d505d185bc3f73deb82d8c8 100644 GIT binary patch delta 58 zcmbQVlDT&!^9HuVLJSN6-s~LjgmpxO85kG@fp{|G5t+@Fhj|4#;i8lMuh_Cl90p1< F006kR4V3@@ delta 63 zcmeBO$vkN#^9HuV;umziu9-411bDM^Y=1l>OoD-dK@5l|PdqHM+2k; Date: Sun, 10 Jun 2018 12:51:06 -0700 Subject: [PATCH 03/18] Avoid obfuscating the class name if the class contains a field annotated with `@State`, see #43 --- CHANGELOG.md | 4 + demo-java-8/proguard.cfg | 4 +- .../state/test/java8/ProguardTest.java | 17 +- .../desugar/runtime/ThrowableExtension.java | 361 ++++++++++++++++++ .../com/evernote/different/TestProguard.java | 10 +- .../different/TestProguardHelper.java | 23 ++ gradle/gradle-quality.gradle | 1 + library/proguard.cfg | 10 +- 8 files changed, 409 insertions(+), 21 deletions(-) create mode 100644 demo-java-8/src/androidTest/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtension.java create mode 100644 demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d693e9..f3d3c6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.1 + +* Avoid obfuscating the class name if the class contains a field annotated with `@State`, see #43 + ## 1.3.0 (2018-05-28) * Support incremental annotation processing, see #48 diff --git a/demo-java-8/proguard.cfg b/demo-java-8/proguard.cfg index cec2751..450851c 100644 --- a/demo-java-8/proguard.cfg +++ b/demo-java-8/proguard.cfg @@ -9,12 +9,11 @@ -ignorewarnings -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*, !method/inlining/unique, !method/inlining/short - +-printconfiguration "build/outputs/mapping/configuration.txt" # Proguard rules that are applied to your test apk/code. -keepattributes *Annotation* --keep class com.evernote.android.state.demo.ProguardTest { *; } -keep class junit.framework.** { *; } -keep class junit.runner.** { *; } @@ -23,5 +22,6 @@ -keep class org.junit.** { *; } -keep class org.hamcrest.** { *; } -keep class com.squareup.javawriter.JavaWriter { *; } +-keep class com.google.devtools.** { *; } # Uncomment this if you use Mockito #-dontwarn org.mockito.** \ No newline at end of file diff --git a/demo-java-8/src/androidTest/java/com/evernote/android/state/test/java8/ProguardTest.java b/demo-java-8/src/androidTest/java/com/evernote/android/state/test/java8/ProguardTest.java index 713ca72..43952f1 100644 --- a/demo-java-8/src/androidTest/java/com/evernote/android/state/test/java8/ProguardTest.java +++ b/demo-java-8/src/androidTest/java/com/evernote/android/state/test/java8/ProguardTest.java @@ -6,6 +6,7 @@ import com.evernote.android.state.StateSaver; import com.evernote.different.TestProguard; import com.evernote.different.TestProguardBundler; +import com.evernote.different.TestProguardHelper; import org.junit.Test; import org.junit.runner.RunWith; @@ -19,27 +20,29 @@ public class ProguardTest { @Test public void testProguardRules() { TestProguard data = new TestProguard(); - data.verifyValue(0); - data.setValue(1); + TestProguardHelper.verifyValue(data, 0); + TestProguardHelper.setValue(data, 1); Bundle bundle = new Bundle(); StateSaver.saveInstanceState(data, bundle); - data.setValue(0); - data.verifyValue(0); + TestProguardHelper.setValue(data, 0); + TestProguardHelper.verifyValue(data, 0); StateSaver.restoreInstanceState(data, bundle); - data.verifyValue(1); + TestProguardHelper.verifyValue(data, 1); } @Test public void verifyCodeObfuscated() throws Exception { TestProguard.class.getDeclaredField("test1"); // test1 - TestProguard.class.getDeclaredField("a"); // test2 +// TestProguard.class.getDeclaredField("a"); // test2 + TestProguard.class.getDeclaredField("test2"); // test2 TestProguard.class.getDeclaredField("test3"); TestProguard.class.getDeclaredMethod("a"); // getTest2() - TestProguardBundler.class.getDeclaredField("a"); // mData2 +// TestProguardBundler.class.getDeclaredField("a"); // mData2 + TestProguardBundler.class.getDeclaredField("mData2"); // mData2 TestProguardBundler.class.getDeclaredField("mDataReflOtherName"); TestProguardBundler.class.getDeclaredMethod("a"); // getData2() } diff --git a/demo-java-8/src/androidTest/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtension.java b/demo-java-8/src/androidTest/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtension.java new file mode 100644 index 0000000..d19b5d1 --- /dev/null +++ b/demo-java-8/src/androidTest/java/com/google/devtools/build/android/desugar/runtime/ThrowableExtension.java @@ -0,0 +1,361 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// 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.devtools.build.android.desugar.runtime; +import java.io.Closeable; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +/** + * This is an extension class for java.lang.Throwable. It emulates the methods + * addSuppressed(Throwable) and getSuppressed(), so the language feature try-with-resources can be + * used on Android devices whose API level is below 19. + * + *

Note that the Desugar should avoid desugaring this class. + */ +public final class ThrowableExtension { + static final AbstractDesugaringStrategy STRATEGY; + /** + * This property allows users to change the desugared behavior of try-with-resources at runtime. + * If its value is {@code true}, then {@link MimicDesugaringStrategy} will NOT be used, and {@link + * NullDesugaringStrategy} is used instead. + * + *

Note: this property is ONLY used when the API level on the device is below 19. + */ + public static final String SYSTEM_PROPERTY_TWR_DISABLE_MIMIC = + "com.google.devtools.build.android.desugar.runtime.twr_disable_mimic"; + // Visible for testing. + static final int API_LEVEL; + static { + AbstractDesugaringStrategy strategy; + Integer apiLevel = null; + try { + apiLevel = readApiLevelFromBuildVersion(); + if (apiLevel != null && apiLevel.intValue() >= 19) { + strategy = new ReuseDesugaringStrategy(); + } else if (useMimicStrategy()) { + strategy = new MimicDesugaringStrategy(); + } else { + strategy = new NullDesugaringStrategy(); + } + } catch (Throwable e) { + // This catchall block is intentionally created to avoid anything unexpected, so that + // the desugared app will continue running in case of exceptions. + System.err.println( + "An error has occured when initializing the try-with-resources desuguring strategy. " + + "The default strategy " + + NullDesugaringStrategy.class.getName() + + "will be used. The error is: "); + e.printStackTrace(System.err); + strategy = new NullDesugaringStrategy(); + } + STRATEGY = strategy; + API_LEVEL = apiLevel == null ? 1 : apiLevel.intValue(); + } + public static AbstractDesugaringStrategy getStrategy() { + return STRATEGY; + } + public static void addSuppressed(Throwable receiver, Throwable suppressed) { + STRATEGY.addSuppressed(receiver, suppressed); + } + public static Throwable[] getSuppressed(Throwable receiver) { + return STRATEGY.getSuppressed(receiver); + } + public static void printStackTrace(Throwable receiver) { + STRATEGY.printStackTrace(receiver); + } + public static void printStackTrace(Throwable receiver, PrintWriter writer) { + STRATEGY.printStackTrace(receiver, writer); + } + public static void printStackTrace(Throwable receiver, PrintStream stream) { + STRATEGY.printStackTrace(receiver, stream); + } + public static void closeResource(Throwable throwable, Object resource) throws Throwable { + if (resource == null) { + return; + } + try { + if (API_LEVEL >= 19) { + ((AutoCloseable) resource).close(); + } else { + if (resource instanceof Closeable) { + ((Closeable) resource).close(); + } else { + try { + Method method = resource.getClass().getMethod("close"); + method.invoke(resource); + } catch (NoSuchMethodException | SecurityException e) { + throw new AssertionError(resource.getClass() + " does not have a close() method.", e); + } catch (IllegalAccessException + | IllegalArgumentException + | ExceptionInInitializerError e) { + throw new AssertionError("Fail to call close() on " + resource.getClass(), e); + } catch (InvocationTargetException e) { + // Exception occurs during the invocation to the close method. The cause is the real + // exception. + Throwable cause = e.getCause(); + throw cause; + } + } + } + } catch (Throwable e) { + if (throwable != null) { + addSuppressed(throwable, e); + throw throwable; + } else { + throw e; + } + } + } + private static boolean useMimicStrategy() { + return !Boolean.getBoolean(SYSTEM_PROPERTY_TWR_DISABLE_MIMIC); + } + private static final String ANDROID_OS_BUILD_VERSION = "android.os.Build$VERSION"; + /** + * Get the API level from {@link android.os.Build.VERSION} via reflection. The reason to use + * relection is to avoid dependency on {@link android.os.Build.VERSION}. The advantage of doing + * this is that even when you desugar a jar twice, and Desugars sees this class, there is no need + * to put {@link android.os.Build.VERSION} on the classpath. + * + *

Another reason of doing this is that it does not introduce any additional dependency into + * the input jars. + * + * @return The API level of the current device. If it is {@code null}, then it means there was an + * exception. + */ + private static Integer readApiLevelFromBuildVersion() { + try { + Class buildVersionClass = Class.forName(ANDROID_OS_BUILD_VERSION); + Field field = buildVersionClass.getField("SDK_INT"); + return (Integer) field.get(null); + } catch (Exception e) { + System.err.println( + "Failed to retrieve value from " + + ANDROID_OS_BUILD_VERSION + + ".SDK_INT due to the following exception."); + e.printStackTrace(System.err); + return null; + } + } + /** + * The strategy to desugar try-with-resources statements. A strategy handles the behavior of an + * exception in terms of suppressed exceptions and stack trace printing. + */ + abstract static class AbstractDesugaringStrategy { + protected static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0]; + public abstract void addSuppressed(Throwable receiver, Throwable suppressed); + public abstract Throwable[] getSuppressed(Throwable receiver); + public abstract void printStackTrace(Throwable receiver); + public abstract void printStackTrace(Throwable receiver, PrintStream stream); + public abstract void printStackTrace(Throwable receiver, PrintWriter writer); + } + /** This strategy just delegates all the method calls to java.lang.Throwable. */ + static final class ReuseDesugaringStrategy extends AbstractDesugaringStrategy { + @Override + public void addSuppressed(Throwable receiver, Throwable suppressed) { + receiver.addSuppressed(suppressed); + } + @Override + public Throwable[] getSuppressed(Throwable receiver) { + return receiver.getSuppressed(); + } + @Override + public void printStackTrace(Throwable receiver) { + receiver.printStackTrace(); + } + @Override + public void printStackTrace(Throwable receiver, PrintStream stream) { + receiver.printStackTrace(stream); + } + @Override + public void printStackTrace(Throwable receiver, PrintWriter writer) { + receiver.printStackTrace(writer); + } + } + /** This strategy mimics the behavior of suppressed exceptions with a map. */ + static final class MimicDesugaringStrategy extends AbstractDesugaringStrategy { + static final String SUPPRESSED_PREFIX = "Suppressed: "; + private final ConcurrentWeakIdentityHashMap map = new ConcurrentWeakIdentityHashMap(); + /** + * Suppress an exception. If the exception to be suppressed is {@receiver} or {@null}, an + * exception will be thrown. + */ + @Override + public void addSuppressed(Throwable receiver, Throwable suppressed) { + if (suppressed == receiver) { + throw new IllegalArgumentException("Self suppression is not allowed.", suppressed); + } + if (suppressed == null) { + throw new NullPointerException("The suppressed exception cannot be null."); + } + // The returned list is a synchrnozed list. + map.get(receiver, /*createOnAbsence=*/true).add(suppressed); + } + @Override + public Throwable[] getSuppressed(Throwable receiver) { + List list = map.get(receiver, /*createOnAbsence=*/false); + if (list == null || list.isEmpty()) { + return EMPTY_THROWABLE_ARRAY; + } + return list.toArray(EMPTY_THROWABLE_ARRAY); + } + /** + * Print the stack trace for the parameter {@code receiver}. Note that it is deliberate to NOT + * reuse the implementation {@code MimicDesugaringStrategy.printStackTrace(Throwable, + * PrintStream)}, because we are not sure whether the developer prints the stack trace to a + * different stream other than System.err. Therefore, it is a caveat that the stack traces of + * {@code receiver} and its suppressed exceptions are printed in two different streams. + */ + @Override + public void printStackTrace(Throwable receiver) { + receiver.printStackTrace(); + List suppressedList = map.get(receiver, /*createOnAbsence=*/false); + if (suppressedList == null) { + return; + } + synchronized (suppressedList) { + for (Throwable suppressed : suppressedList) { + System.err.print(SUPPRESSED_PREFIX); + suppressed.printStackTrace(); + } + } + } + @Override + public void printStackTrace(Throwable receiver, PrintStream stream) { + receiver.printStackTrace(stream); + List suppressedList = map.get(receiver, /*createOnAbsence=*/false); + if (suppressedList == null) { + return; + } + synchronized (suppressedList) { + for (Throwable suppressed : suppressedList) { + stream.print(SUPPRESSED_PREFIX); + suppressed.printStackTrace(stream); + } + } + } + @Override + public void printStackTrace(Throwable receiver, PrintWriter writer) { + receiver.printStackTrace(writer); + List suppressedList = map.get(receiver, /*createOnAbsence=*/false); + if (suppressedList == null) { + return; + } + synchronized (suppressedList) { + for (Throwable suppressed : suppressedList) { + writer.print(SUPPRESSED_PREFIX); + suppressed.printStackTrace(writer); + } + } + } + } + /** A hash map, that is concurrent, weak-key, and identity-hashing. */ + static final class ConcurrentWeakIdentityHashMap { + private final ConcurrentHashMap> map = + new ConcurrentHashMap<>(16, 0.75f, 10); + private final ReferenceQueue referenceQueue = new ReferenceQueue<>(); + /** + * @param throwable, the key to retrieve or create associated list. + * @param createOnAbsence {@code true} to create a new list if there is no value for the key. + * @return the associated value with the given {@code throwable}. If {@code createOnAbsence} is + * {@code true}, the returned value will be non-null. Otherwise, it can be {@code null} + */ + public List get(Throwable throwable, boolean createOnAbsence) { + deleteEmptyKeys(); + WeakKey keyForQuery = new WeakKey(throwable, null); + List list = map.get(keyForQuery); + if (!createOnAbsence) { + return list; + } + if (list != null) { + return list; + } + List newValue = new Vector<>(2); + list = map.putIfAbsent(new WeakKey(throwable, referenceQueue), newValue); + return list == null ? newValue : list; + } + /** For testing-purpose */ + int size() { + return map.size(); + } + void deleteEmptyKeys() { + // The ReferenceQueue.poll() is thread-safe. + for (Reference key = referenceQueue.poll(); key != null; key = referenceQueue.poll()) { + map.remove(key); + } + } + private static final class WeakKey extends WeakReference { + /** + * The hash code is used later to retrieve the entry, of which the key is the current weak + * key. If the referent is marked for garbage collection and is set to null, we are still able + * to locate the entry. + */ + private final int hash; + public WeakKey(Throwable referent, ReferenceQueue q) { + super(referent, q); + if (referent == null) { + throw new NullPointerException("The referent cannot be null"); + } + hash = System.identityHashCode(referent); + } + @Override + public int hashCode() { + return hash; + } + @Override + public boolean equals(Object obj) { + if (obj == null || obj.getClass() != getClass()) { + return false; + } + if (this == obj) { + return true; + } + WeakKey other = (WeakKey) obj; + // Note that, after the referent is garbage collected, then the referent will be null. + // And the equality test still holds. + return this.hash == other.hash && this.get() == other.get(); + } + } + } + /** This strategy ignores all suppressed exceptions, which is how retrolambda does. */ + static final class NullDesugaringStrategy extends AbstractDesugaringStrategy { + @Override + public void addSuppressed(Throwable receiver, Throwable suppressed) { + // Do nothing. The suppressed exception is discarded. + } + @Override + public Throwable[] getSuppressed(Throwable receiver) { + return EMPTY_THROWABLE_ARRAY; + } + @Override + public void printStackTrace(Throwable receiver) { + receiver.printStackTrace(); + } + @Override + public void printStackTrace(Throwable receiver, PrintStream stream) { + receiver.printStackTrace(stream); + } + @Override + public void printStackTrace(Throwable receiver, PrintWriter writer) { + receiver.printStackTrace(writer); + } + } +} \ No newline at end of file diff --git a/demo-java-8/src/main/java/com/evernote/different/TestProguard.java b/demo-java-8/src/main/java/com/evernote/different/TestProguard.java index 82bb606..cce9deb 100644 --- a/demo-java-8/src/main/java/com/evernote/different/TestProguard.java +++ b/demo-java-8/src/main/java/com/evernote/different/TestProguard.java @@ -1,8 +1,6 @@ package com.evernote.different; // different package to avoid clash with Proguard rules -import android.support.annotation.Keep; - import com.evernote.android.state.State; import com.evernote.android.state.StateReflection; @@ -28,23 +26,21 @@ public void setTest2(int test2) { this.test2 = test2; } - @Keep public void setValue(int value) { test1 = value; setTest2(value); test3 = value; } - @Keep public void verifyValue(int value) { if (test1 != value) { - throw new IllegalStateException(); + throw new IllegalStateException("test1 different, expected " + value + ", is " + test1); } if (getTest2() != value) { - throw new IllegalStateException(); + throw new IllegalStateException("getTest2() different, expected " + value + ", is " + getTest2()); } if (test3 != value) { - throw new IllegalStateException(); + throw new IllegalStateException("test3 different, expected " + value + ", is " + test3); } } } diff --git a/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java b/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java new file mode 100644 index 0000000..7ab94ae --- /dev/null +++ b/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java @@ -0,0 +1,23 @@ +package com.evernote.different; + +import android.support.annotation.Keep; + +/** + * @author rwondratschek + */ +public final class TestProguardHelper { + + private TestProguardHelper() { + // no op + } + + @Keep + public static void setValue(TestProguard instance, int value) { + instance.setValue(value); + } + + @Keep + public static void verifyValue(TestProguard instance, int value) { + instance.verifyValue(value); + } +} diff --git a/gradle/gradle-quality.gradle b/gradle/gradle-quality.gradle index b679470..160fb05 100644 --- a/gradle/gradle-quality.gradle +++ b/gradle/gradle-quality.gradle @@ -13,6 +13,7 @@ task checkstyle(type: Checkstyle) { include '**/*.java' exclude '**/gen/**' exclude '**/test/resources/**' + exclude '**/com/google/devtools/**' classpath = files() } diff --git a/library/proguard.cfg b/library/proguard.cfg index dbe6d01..fe06489 100644 --- a/library/proguard.cfg +++ b/library/proguard.cfg @@ -3,13 +3,13 @@ -keep class **$$StateSaver { *; } # generated class names --keepclasseswithmembernames class * { @com.evernote.android.state.State *;} --keepclasseswithmembernames class * { @com.evernote.android.state.StateReflection *;} +-keepclasseswithmembernames class * { @com.evernote.android.state.State ;} +-keepclasseswithmembernames class * { @com.evernote.android.state.StateReflection ;} # only keep non-private fields, there must be a getter / setter for private fields --keepclassmembers class * { - @com.evernote.android.state.State !private ; -} +#-keepclassmembers class * { +# @com.evernote.android.state.State !private ; +#} # with reflection always keep the name of the field -keepclassmembers class * { @com.evernote.android.state.StateReflection ;} \ No newline at end of file From 44f6762249db042fbaa75670f29f71a833e8b4fb Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 10 Jun 2018 12:55:06 -0700 Subject: [PATCH 04/18] Enforce the new Kotlin JDK libraries --- build.gradle | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/build.gradle b/build.gradle index 2848728..dd7f67d 100644 --- a/build.gradle +++ b/build.gradle @@ -53,5 +53,19 @@ subprojects { subproject -> // avoids conflicts in test app configurations.all { resolutionStrategy.force "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" + + // Replace deprecated Kotlin JRE dependencies with JDK dependencies + resolutionStrategy.dependencySubstitution { + all { DependencySubstitution dependency -> + if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.group == 'org.jetbrains.kotlin') { + if (dependency.requested.module == 'kotlin-stdlib-jre7') { + dependency.useTarget "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + } + if (dependency.requested.module == 'kotlin-stdlib-jre8') { + dependency.useTarget "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" + } + } + } + } } } \ No newline at end of file From f7a4dbff71c814fec412f1cb9fed70490e88c391 Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 10 Jun 2018 15:12:16 -0700 Subject: [PATCH 05/18] Don't use the serializable type for parcelable arrays, see #53 --- CHANGELOG.md | 1 + .../android/state/test/BundlingTest.java | 17 ++++++++ .../state/test/TestParcelableArray.java | 36 +++++++++++++++++ .../android/state/test/TestTypes.java | 4 ++ .../android/state/test/KotlinBundlingTest.kt | 30 ++++++++++++-- .../state/test/TestKotlinParcelableArray.kt | 24 +++++++++++ .../android/state/StateProcessor.java | 39 ++++++++++++++++-- .../evernote/android/state/TestProcessor.java | 40 +++++++++++++++---- 8 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 library/src/test/java/com/evernote/android/state/test/TestParcelableArray.java create mode 100644 library/src/test/kotlin/com/evernote/android/state/test/TestKotlinParcelableArray.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index f3d3c6a..d67feda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 1.3.1 * Avoid obfuscating the class name if the class contains a field annotated with `@State`, see #43 +* Don't use the serializable type for parcelable arrays, see #53 ## 1.3.0 (2018-05-28) diff --git a/library/src/test/java/com/evernote/android/state/test/BundlingTest.java b/library/src/test/java/com/evernote/android/state/test/BundlingTest.java index baf5c74..c8c7d33 100644 --- a/library/src/test/java/com/evernote/android/state/test/BundlingTest.java +++ b/library/src/test/java/com/evernote/android/state/test/BundlingTest.java @@ -317,6 +317,23 @@ public void testPrivateInnerClass() { assertThat(testPrivateInnerClass.isB()).isTrue(); } + @Test + public void testParcelableArray() { + TestParcelableArray testParcelableArray = createSavedInstance(TestParcelableArray.class); + testParcelableArray.setToValue(1); + + StateSaver.restoreInstanceState(testParcelableArray, mBundle); + assertThat(testParcelableArray.isValue(0)).isTrue(); + + testParcelableArray.setToValue(1); + + StateSaver.saveInstanceState(testParcelableArray, mBundle); + testParcelableArray.setToValue(0); + + StateSaver.restoreInstanceState(testParcelableArray, mBundle); + assertThat(testParcelableArray.isValue(1)).isTrue(); + } + private T createSavedInstance(Class clazz) { try { T instance = clazz.newInstance(); diff --git a/library/src/test/java/com/evernote/android/state/test/TestParcelableArray.java b/library/src/test/java/com/evernote/android/state/test/TestParcelableArray.java new file mode 100644 index 0000000..141d93a --- /dev/null +++ b/library/src/test/java/com/evernote/android/state/test/TestParcelableArray.java @@ -0,0 +1,36 @@ +package com.evernote.android.state.test; + +import com.evernote.android.state.State; +import com.evernote.android.state.StateReflection; + +/** + * @author rwondratschek + */ +public class TestParcelableArray { + @State + public TestTypes.ParcelableImpl[] mParcelableArrayImpl1 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(0)}; + + @State + private TestTypes.ParcelableImpl[] mParcelableArrayImpl2 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(0)}; + + @StateReflection + private TestTypes.ParcelableImpl[] mParcelableArrayImpl3 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(0)}; + + public TestTypes.ParcelableImpl[] getParcelableArrayImpl2() { + return mParcelableArrayImpl2; + } + + public void setParcelableArrayImpl2(TestTypes.ParcelableImpl[] parcelableArrayImpl2) { + mParcelableArrayImpl2 = parcelableArrayImpl2; + } + + public void setToValue(int value) { + mParcelableArrayImpl1 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(value)}; + mParcelableArrayImpl2 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(value)}; + mParcelableArrayImpl3 = new TestTypes.ParcelableImpl[]{new TestTypes.ParcelableImpl(value)}; + } + + public boolean isValue(int value) { + return mParcelableArrayImpl1[0].isValue(value) && mParcelableArrayImpl2[0].isValue(value) && mParcelableArrayImpl3[0].isValue(value); + } +} diff --git a/library/src/test/java/com/evernote/android/state/test/TestTypes.java b/library/src/test/java/com/evernote/android/state/test/TestTypes.java index b1096eb..08fb393 100644 --- a/library/src/test/java/com/evernote/android/state/test/TestTypes.java +++ b/library/src/test/java/com/evernote/android/state/test/TestTypes.java @@ -97,6 +97,10 @@ protected ParcelableImpl(Parcel in) { mInt = in.readInt(); } + public boolean isValue(int value) { + return mInt == value; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/library/src/test/kotlin/com/evernote/android/state/test/KotlinBundlingTest.kt b/library/src/test/kotlin/com/evernote/android/state/test/KotlinBundlingTest.kt index d3780ea..7d29c7b 100644 --- a/library/src/test/kotlin/com/evernote/android/state/test/KotlinBundlingTest.kt +++ b/library/src/test/kotlin/com/evernote/android/state/test/KotlinBundlingTest.kt @@ -195,8 +195,8 @@ class KotlinBundlingTest { @Test fun testPrivateInnerClass() { - val item = TestPrivateInnerClass() - assertThat(item.isA).isTrue() + val item = TestKotlinPrivateInnerClass() + assertThat(item.isA()).isTrue() val bundle = Bundle() StateSaver.saveInstanceState(item, bundle) @@ -204,7 +204,7 @@ class KotlinBundlingTest { item.setToB() StateSaver.restoreInstanceState(item, bundle) - assertThat(item.isA).isTrue() + assertThat(item.isA()).isTrue() item.setToB() StateSaver.saveInstanceState(item, bundle) @@ -212,6 +212,28 @@ class KotlinBundlingTest { item.setToA() StateSaver.restoreInstanceState(item, bundle) - assertThat(item.isB).isTrue() + assertThat(item.isB()).isTrue() + } + + @Test + fun testParcelableArray() { + val item = TestKotlinParcelableArray() + assertThat(item.isValue(0)).isTrue() + + val bundle = Bundle() + StateSaver.saveInstanceState(item, bundle) + + item.setToValue(1) + + StateSaver.restoreInstanceState(item, bundle) + assertThat(item.isValue(0)).isTrue() + + item.setToValue(1) + StateSaver.saveInstanceState(item, bundle) + + item.setToValue(0) + + StateSaver.restoreInstanceState(item, bundle) + assertThat(item.isValue(1)).isTrue() } } \ No newline at end of file diff --git a/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinParcelableArray.kt b/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinParcelableArray.kt new file mode 100644 index 0000000..a526ce0 --- /dev/null +++ b/library/src/test/kotlin/com/evernote/android/state/test/TestKotlinParcelableArray.kt @@ -0,0 +1,24 @@ +package com.evernote.android.state.test + +import com.evernote.android.state.State +import com.evernote.android.state.StateReflection + +/** + * @author rwondratschek + */ +class TestKotlinParcelableArray { + @State + var parcelableArrayImpl1: Array = arrayOf(TestTypes.ParcelableImpl(0)) + + @StateReflection + private var mParcelableArrayImpl2: Array = arrayOf(TestTypes.ParcelableImpl(0)) + + fun setToValue(value: Int) { + parcelableArrayImpl1 = arrayOf(TestTypes.ParcelableImpl(value)) + mParcelableArrayImpl2 = arrayOf(TestTypes.ParcelableImpl(value)) + } + + fun isValue(value: Int): Boolean { + return parcelableArrayImpl1[0].isValue(value) && mParcelableArrayImpl2[0].isValue(value) + } +} \ No newline at end of file diff --git a/processor/src/main/java/com/evernote/android/state/StateProcessor.java b/processor/src/main/java/com/evernote/android/state/StateProcessor.java index a60e40f..d30be42 100644 --- a/processor/src/main/java/com/evernote/android/state/StateProcessor.java +++ b/processor/src/main/java/com/evernote/android/state/StateProcessor.java @@ -57,6 +57,7 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; @@ -118,6 +119,7 @@ public int compare(Element o1, Element o2) { private static final String STATE_REFLECTION_CLASS_NAME = StateReflection.class.getName(); private static final String OBJECT_CLASS_NAME = Object.class.getName(); private static final String PARCELABLE_CLASS_NAME = Parcelable.class.getName(); + private static final String PARCELABLE_ARRAY_CLASS_NAME = Parcelable[].class.getCanonicalName(); private static final String SERIALIZABLE_CLASS_NAME = Serializable.class.getName(); private static final Set GENERIC_SUPER_TYPES = Collections.unmodifiableSet(new HashSet() {{ @@ -317,6 +319,13 @@ public boolean process(Set annotations, RoundEnvironment String fieldName = fieldType.getFieldName(field); + String castedType = null; + CompatibilityType compatibilityType = getCompatibilityType(field); + if (compatibilityType == CompatibilityType.PARCELABLE_ARRAY && !PARCELABLE_ARRAY_CLASS_NAME.equals(fieldTypeString)) { + mMessager.printMessage(Diagnostic.Kind.NOTE, "Field " + fieldTypeString + " " + PARCELABLE_ARRAY_CLASS_NAME); + castedType = fieldTypeString; + } + BundlerWrapper bundler = bundlers.get(field); if (bundler != null) { staticInitBlock = staticInitBlock.addStatement("BUNDLERS.put($S, new $T())", fieldName, bundler.mBundlerName); @@ -326,7 +335,11 @@ public boolean process(Set annotations, RoundEnvironment switch (fieldType) { case FIELD: saveMethodBuilder = saveMethodBuilder.addStatement("HELPER.put$N(state, $S, target.$N)", mapping, fieldName, fieldName); - restoreMethodBuilder = restoreMethodBuilder.addStatement("target.$N = HELPER.get$N(state, $S)", fieldName, mapping, fieldName); + if (castedType != null) { + restoreMethodBuilder = restoreMethodBuilder.addStatement("target.$N = ($N) HELPER.get$N(state, $S)", fieldName, castedType, mapping, fieldName); + } else { + restoreMethodBuilder = restoreMethodBuilder.addStatement("target.$N = HELPER.get$N(state, $S)", fieldName, mapping, fieldName); + } break; case BOOLEAN_PROPERTY: @@ -356,6 +369,9 @@ public boolean process(Set annotations, RoundEnvironment if (insertedType != null) { restoreMethodBuilder = restoreMethodBuilder.addStatement("target.set$N(HELPER.<$T>get$N(state, $S))", fieldName, ClassName.get(insertedType.mTypeMirror), mapping, fieldName); + } else if (castedType != null) { + restoreMethodBuilder = restoreMethodBuilder.addStatement("target.set$N(($N) HELPER.get$N(state, $S))", + fieldName, castedType, mapping, fieldName); } else { restoreMethodBuilder = restoreMethodBuilder.addStatement("target.set$N(HELPER.get$N(state, $S))", fieldName, mapping, fieldName); @@ -366,7 +382,6 @@ public boolean process(Set annotations, RoundEnvironment case FIELD_REFLECTION: String reflectionMapping = isPrimitiveMapping(mapping) ? mapping : ""; - CompatibilityType compatibilityType = getCompatibilityType(field); InsertedTypeResult insertedType = getInsertedType(field, true); if (compatibilityType != null && insertedType != null) { // either serializable or parcelable, this could be a private inner class, so don't use the concrete type @@ -486,7 +501,7 @@ private boolean writeJavaFile(JavaFile javaFile) { } } - public HashMap> getMapGeneratedFileToOriginatingElements() { + /*package*/ HashMap> getMapGeneratedFileToOriginatingElements() { return mMapGeneratedFileToOriginatingElements; } @@ -786,6 +801,7 @@ private BundlerWrapper(TypeName bundlerName, TypeName genericName) { @SuppressWarnings("unused") private enum CompatibilityType { PARCELABLE("Parcelable", Parcelable.class, null), + PARCELABLE_ARRAY("ParcelableArray", Parcelable[].class, null), PARCELABLE_LIST("ParcelableArrayList", ArrayList.class, Parcelable.class), SPARSE_PARCELABLE_ARRAY("SparseParcelableArray", SparseArray.class, Parcelable.class), SERIALIZABLE("Serializable", Serializable.class, null); @@ -804,7 +820,13 @@ private enum CompatibilityType { private CompatibilityType getCompatibilityType(Element field) { TypeMirror typeMirror = field.asType(); for (CompatibilityType compatibilityType : CompatibilityType.values()) { - if (compatibilityType.mGenericClass == null) { + if (compatibilityType == CompatibilityType.PARCELABLE_ARRAY) { + TypeMirror arrayType = getArrayType(field); + if (arrayType != null && isAssignable(arrayType, Parcelable.class)) { + return CompatibilityType.PARCELABLE_ARRAY; + } + + } else if (compatibilityType.mGenericClass == null) { if (isAssignable(typeMirror, compatibilityType.mClass)) { return compatibilityType; } @@ -821,6 +843,15 @@ private CompatibilityType getCompatibilityType(Element field) { return null; } + private TypeMirror getArrayType(Element field) { + TypeMirror typeMirror = field.asType(); + if (typeMirror instanceof ArrayType) { + return ((ArrayType) typeMirror).getComponentType(); + } else { + return null; + } + } + @SuppressWarnings("SameParameterValue") private boolean isAssignable(Element element, Class clazz) { return isAssignable(element.asType(), clazz); diff --git a/processor/src/test/java/com/evernote/android/state/TestProcessor.java b/processor/src/test/java/com/evernote/android/state/TestProcessor.java index 9480ffa..29c1b82 100644 --- a/processor/src/test/java/com/evernote/android/state/TestProcessor.java +++ b/processor/src/test/java/com/evernote/android/state/TestProcessor.java @@ -15,7 +15,6 @@ import com.google.testing.compile.JavaFileObjects; import org.junit.FixMethodOrder; -import org.junit.Ignore; import org.junit.Test; import org.junit.runners.MethodSorters; @@ -651,6 +650,34 @@ public void testAllTypes() { + "}\n"); JavaFileObject expected = JavaFileObjects.forSourceString(getName(className, true), "" + + "/* *****************************************************************************\n" + + " * Copyright (c) 2017 Evernote Corporation.\n" + + " * This software was generated by Evernote’s Android-State code generator\n" + + " * (available at https://github.com/evernote/android-state), which is made\n" + + " * available under the terms of the Eclipse Public License v1.0\n" + + " * (available at http://www.eclipse.org/legal/epl-v10.html).\n" + + " * For clarification, code generated by the Android-State code generator is\n" + + " * not subject to the Eclipse Public License and can be used subject to the\n" + + " * following terms:\n" + + " *\n" + + " * Permission is hereby granted, free of charge, to any person obtaining a copy\n" + + " * of this software and associated documentation files (the \"Software\"), to deal\n" + + " * in the Software without restriction, including without limitation the rights\n" + + " * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n" + + " * copies of the Software, and to permit persons to whom the Software is\n" + + " * furnished to do so, subject to the following conditions:\n" + + " *\n" + + " * The above copyright notice and this permission notice shall be included in all\n" + + " * copies or substantial portions of the Software.\n" + + " *\n" + + " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n" + + " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" + + " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n" + + " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n" + + " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n" + + " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n" + + " * SOFTWARE.\n" + + " *******************************************************************************/\n" + "package com.evernote.android.state.test;\n" + "\n" + "import android.os.Bundle;\n" @@ -753,7 +780,7 @@ public void testAllTypes() { + " target.mShort = HELPER.getShort(state, \"mShort\");\n" + " target.mShortArray = HELPER.getShortArray(state, \"mShortArray\");\n" + " }\n" - + "}\n"); + + "}"); Compilation compilation = Compiler.javac().withProcessors(new StateProcessor()).compile(javaFileObject); assertThat(compilation).succeeded(); @@ -761,7 +788,6 @@ public void testAllTypes() { } @Test - @Ignore public void testReflection() { String className = "TestTypesReflection"; JavaFileObject javaFileObject = JavaFileObjects.forSourceString(getName(className), "" @@ -1043,8 +1069,7 @@ public void testReflection() { + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putSparseParcelableArray(state, \"mParcelableSparseArray\", " - + "(android.util.SparseArray) field.get(target));\n" + + " HELPER.putSparseParcelableArray(state, \"mParcelableSparseArray\", (android.util.SparseArray) field.get(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1096,8 +1121,7 @@ public void testReflection() { + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putSerializable(state, \"mParcelableArrayList\", (java.util.ArrayList) field.get(target));\n" + + " HELPER.putSerializable(state, \"mParcelableArrayList\", (java.io.Serializable) field.get(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1201,7 +1225,7 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " }\n" - + "}\n"); + + "}"); Compilation compilation = Compiler.javac().withProcessors(new StateProcessor()).compile(javaFileObject, javaFileObjectInnerClass); assertThat(compilation).succeeded(); From 1fad7000a3434f1febcf3847a37ed6074c0849c4 Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 10 Jun 2018 15:25:53 -0700 Subject: [PATCH 06/18] Publish version 1.3.1 --- CHANGELOG.md | 2 +- README.md | 6 +++--- gradle.properties | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d67feda..89434e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.3.1 +## 1.3.1 (2018-06-10) * Avoid obfuscating the class name if the class contains a field annotated with `@State`, see #43 * Don't use the serializable type for parcelable arrays, see #53 diff --git a/README.md b/README.md index 77138a4..9ccce0e 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ Download the latest [library](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%2 ```groovy dependencies { - implementation 'com.evernote:android-state:1.3.0' + implementation 'com.evernote:android-state:1.3.1' // Java only project - annotationProcessor 'com.evernote:android-state-processor:1.3.0' + annotationProcessor 'com.evernote:android-state-processor:1.3.1' // Kotlin with or without Java - kapt 'com.evernote:android-state-processor:1.3.0' + kapt 'com.evernote:android-state-processor:1.3.1' } ``` diff --git a/gradle.properties b/gradle.properties index 5c351a4..59a54d0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -#VERSION_NAME=1.3.0 -VERSION_NAME=1.3.0-SNAPSHOT +#VERSION_NAME=1.3.1 +VERSION_NAME=1.3.1-SNAPSHOT VERSION_CODE=1 \ No newline at end of file From eac8d175c7e180018d6c5db034ed427cf93205eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=ADna?= Date: Tue, 19 Jun 2018 01:17:40 +0200 Subject: [PATCH 07/18] Add test case for inner class with generic issue --- .../android/state/test/TestInnerClassGeneric.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 library/src/test/java/com/evernote/android/state/test/TestInnerClassGeneric.java diff --git a/library/src/test/java/com/evernote/android/state/test/TestInnerClassGeneric.java b/library/src/test/java/com/evernote/android/state/test/TestInnerClassGeneric.java new file mode 100644 index 0000000..ae1ee9e --- /dev/null +++ b/library/src/test/java/com/evernote/android/state/test/TestInnerClassGeneric.java @@ -0,0 +1,10 @@ +package com.evernote.android.state.test; + +import com.evernote.android.state.State; + +public class TestInnerClassGeneric

{ + + public class Inner { + @State int field; + } +} From f2e889b9a8621d9a427227052d4daf64fe869776 Mon Sep 17 00:00:00 2001 From: Steven Schoen Date: Wed, 1 Aug 2018 01:17:34 -0700 Subject: [PATCH 08/18] Sort elements by name rather than type The fields accessed by the processor have no guaranteed ordering, which I assume is why `fields` is sorted by type in the first place. In incremental builds, the order seems to change randomly, and this hurts compilation avoidance as then the generated StateSaver classes are different (calls shifted around but functionally not changing). Since `fields` is being sorted by type, fields of the same type still have no guaranteed ordering. This changes them to be sorted by their name rather than their type. I can't think of any problems with sorting them by name, as field names have to be unique within a class. Tested in a large project and a sample project. Thanks for the well-organized project, by the way. --- .../main/java/com/evernote/android/state/StateProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/processor/src/main/java/com/evernote/android/state/StateProcessor.java b/processor/src/main/java/com/evernote/android/state/StateProcessor.java index d30be42..3b3d633 100644 --- a/processor/src/main/java/com/evernote/android/state/StateProcessor.java +++ b/processor/src/main/java/com/evernote/android/state/StateProcessor.java @@ -111,7 +111,7 @@ public class StateProcessor extends AbstractProcessor { private static final Comparator COMPARATOR = new Comparator() { @Override public int compare(Element o1, Element o2) { - return o1.asType().toString().compareTo(o2.asType().toString()); + return o1.getSimpleName().toString().compareTo(o2.getSimpleName().toString()); } }; From eff933070e8b786f79f231a1a07e4326a0bbea13 Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 23 Sep 2018 19:27:59 -0700 Subject: [PATCH 09/18] Upgrade tools and migrate to Android X --- build.gradle | 11 +++++------ demo-java-8/build.gradle | 4 ++-- .../different/TestProguardBundler.java | 6 +++--- .../different/TestProguardHelper.java | 2 +- demo/build.gradle | 2 +- .../test/lint/LintFailingActivityJava.java | 2 +- .../android/state/demo/MainActivity.kt | 4 ++-- gradle.properties | 4 ++-- gradle/wrapper/gradle-wrapper.jar | Bin 54413 -> 56177 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- library/build.gradle | 6 ++++-- .../state/test/GlobalStateSaverTest.kt | 4 ++-- .../state/AndroidLifecycleCallbacks.java | 7 ++++--- .../com/evernote/android/state/Bundler.java | 5 +++-- .../android/state/InjectionHelper.java | 2 +- .../evernote/android/state/StateSaver.java | 4 ++-- .../android/state/StateSaverImpl.java | 4 ++-- .../bundlers/BundlerListCharSequence.java | 4 ++-- .../state/bundlers/BundlerListInteger.java | 4 ++-- .../state/bundlers/BundlerListParcelable.java | 4 ++-- .../state/bundlers/BundlerListString.java | 4 ++-- .../android/state/test/TestBundler.java | 4 ++-- processor/build.gradle | 2 +- 23 files changed, 47 insertions(+), 44 deletions(-) diff --git a/build.gradle b/build.gradle index dd7f67d..78cd5b7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { - ext.kotlinVersion = '1.2.41' - ext.agpVersion = '3.1.1' + ext.kotlinVersion = '1.2.70' + ext.agpVersion = '3.1.4' repositories { google() @@ -27,13 +27,12 @@ allprojects { } ext { - compileSdkVersion = 27 + compileSdkVersion = 28 targetSdkVersion = compileSdkVersion minSdkVersion = 14 - buildToolsVersion = '27.0.3' + buildToolsVersion = '28.0.2' - supportLibVersion = '27.0.2' junitVersion = '4.12' assertjVersion = '3.6.2' lintVersion = "26" + agpVersion.substring(1) @@ -45,7 +44,7 @@ ext { } task wrapper(type: Wrapper) { - gradleVersion = '4.8' + gradleVersion = '4.10.2' distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } diff --git a/demo-java-8/build.gradle b/demo-java-8/build.gradle index f898e6b..1623089 100644 --- a/demo-java-8/build.gradle +++ b/demo-java-8/build.gradle @@ -55,9 +55,9 @@ dependencies { implementation project(':library') annotationProcessor project(':processor') - implementation "com.android.support:appcompat-v7:$supportLibVersion" + implementation "androidx.appcompat:appcompat:1.0.0" - androidTestImplementation "com.android.support:support-annotations:$supportLibVersion" + androidTestImplementation "androidx.annotation:annotation:1.0.0" androidTestImplementation "com.android.support.test:runner:$testRuleVersion" androidTestImplementation "com.android.support.test:rules:testRuleVersion" androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion" diff --git a/demo-java-8/src/main/java/com/evernote/different/TestProguardBundler.java b/demo-java-8/src/main/java/com/evernote/different/TestProguardBundler.java index bdcad72..f5e2f13 100644 --- a/demo-java-8/src/main/java/com/evernote/different/TestProguardBundler.java +++ b/demo-java-8/src/main/java/com/evernote/different/TestProguardBundler.java @@ -1,9 +1,9 @@ package com.evernote.different; import android.os.Bundle; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.evernote.android.state.Bundler; import com.evernote.android.state.State; diff --git a/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java b/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java index 7ab94ae..fa20216 100644 --- a/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java +++ b/demo-java-8/src/main/java/com/evernote/different/TestProguardHelper.java @@ -1,6 +1,6 @@ package com.evernote.different; -import android.support.annotation.Keep; +import androidx.annotation.Keep; /** * @author rwondratschek diff --git a/demo/build.gradle b/demo/build.gradle index c9b3e74..70f29b9 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -37,7 +37,7 @@ android { dependencies { implementation project(':library') kapt project(':processor') - implementation "com.android.support:appcompat-v7:$supportLibVersion" + implementation "androidx.appcompat:appcompat:1.0.0" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" } diff --git a/demo/src/main/java/com/evernote/android/state/test/lint/LintFailingActivityJava.java b/demo/src/main/java/com/evernote/android/state/test/lint/LintFailingActivityJava.java index 7306525..bf0bb8d 100644 --- a/demo/src/main/java/com/evernote/android/state/test/lint/LintFailingActivityJava.java +++ b/demo/src/main/java/com/evernote/android/state/test/lint/LintFailingActivityJava.java @@ -3,7 +3,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import com.evernote.android.state.StateSaver; diff --git a/demo/src/main/kotlin/com/evernote/android/state/demo/MainActivity.kt b/demo/src/main/kotlin/com/evernote/android/state/demo/MainActivity.kt index bc3f095..595af78 100644 --- a/demo/src/main/kotlin/com/evernote/android/state/demo/MainActivity.kt +++ b/demo/src/main/kotlin/com/evernote/android/state/demo/MainActivity.kt @@ -11,8 +11,8 @@ package com.evernote.android.state.demo import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity import android.util.Log import com.evernote.android.state.State diff --git a/gradle.properties b/gradle.properties index 59a54d0..b980f1e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -#VERSION_NAME=1.3.1 -VERSION_NAME=1.3.1-SNAPSHOT +#VERSION_NAME=1.4.0 +VERSION_NAME=1.4.0-SNAPSHOT VERSION_CODE=1 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1948b9074f1016d15d505d185bc3f73deb82d8c8..29953ea141f55e3b8fc691d31b5ca8816d89fa87 100644 GIT binary patch delta 49463 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

Gauk6VzRKaGELdj)1bl0ug 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 Ci1Hf% diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4fc03d..d76b502 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/library/build.gradle b/library/build.gradle index 54d475c..f02d47d 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -13,6 +13,8 @@ android { resourcePrefix 'state_' + useLibrary 'android.test.mock' + defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion @@ -52,7 +54,7 @@ android { } dependencies { - implementation "com.android.support:support-fragment:$supportLibVersion" + implementation "androidx.fragment:fragment:1.0.0" lintChecks project(':library-lint') testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" @@ -66,7 +68,7 @@ dependencies { kaptTest project(':processor') androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" - androidTestImplementation "com.android.support:support-annotations:$supportLibVersion" + androidTestImplementation "androidx.annotation:annotation:1.0.0" androidTestImplementation "com.android.support.test:runner:$testRuleVersion" androidTestImplementation "com.android.support.test:rules:$testRuleVersion" androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoVersion" diff --git a/library/src/androidTest/kotlin/com/evernote/android/state/test/GlobalStateSaverTest.kt b/library/src/androidTest/kotlin/com/evernote/android/state/test/GlobalStateSaverTest.kt index ee31e24..cf8c841 100644 --- a/library/src/androidTest/kotlin/com/evernote/android/state/test/GlobalStateSaverTest.kt +++ b/library/src/androidTest/kotlin/com/evernote/android/state/test/GlobalStateSaverTest.kt @@ -12,8 +12,8 @@ import android.support.test.rule.ActivityTestRule import android.support.test.runner.AndroidJUnit4 import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry import android.support.test.runner.lifecycle.Stage -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity import com.evernote.android.state.State import com.evernote.android.state.StateSaver import org.assertj.core.api.Assertions.assertThat diff --git a/library/src/main/java/com/evernote/android/state/AndroidLifecycleCallbacks.java b/library/src/main/java/com/evernote/android/state/AndroidLifecycleCallbacks.java index 0475d8a..c5ec3c5 100644 --- a/library/src/main/java/com/evernote/android/state/AndroidLifecycleCallbacks.java +++ b/library/src/main/java/com/evernote/android/state/AndroidLifecycleCallbacks.java @@ -3,9 +3,10 @@ import android.app.Activity; import android.app.Application.ActivityLifecycleCallbacks; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; /** * @author rwondratschek diff --git a/library/src/main/java/com/evernote/android/state/Bundler.java b/library/src/main/java/com/evernote/android/state/Bundler.java index 1ad0088..b7976f4 100644 --- a/library/src/main/java/com/evernote/android/state/Bundler.java +++ b/library/src/main/java/com/evernote/android/state/Bundler.java @@ -12,8 +12,9 @@ package com.evernote.android.state; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Helper interface to save any object inside a {@link Bundle}. diff --git a/library/src/main/java/com/evernote/android/state/InjectionHelper.java b/library/src/main/java/com/evernote/android/state/InjectionHelper.java index 4b15a1c..ad5be76 100644 --- a/library/src/main/java/com/evernote/android/state/InjectionHelper.java +++ b/library/src/main/java/com/evernote/android/state/InjectionHelper.java @@ -13,7 +13,7 @@ import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.util.SparseArray; import java.io.Serializable; diff --git a/library/src/main/java/com/evernote/android/state/StateSaver.java b/library/src/main/java/com/evernote/android/state/StateSaver.java index 223c89c..514bb95 100644 --- a/library/src/main/java/com/evernote/android/state/StateSaver.java +++ b/library/src/main/java/com/evernote/android/state/StateSaver.java @@ -14,8 +14,8 @@ import android.app.Application; import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import java.util.LinkedHashMap; diff --git a/library/src/main/java/com/evernote/android/state/StateSaverImpl.java b/library/src/main/java/com/evernote/android/state/StateSaverImpl.java index 105b8cb..f9c2f6e 100644 --- a/library/src/main/java/com/evernote/android/state/StateSaverImpl.java +++ b/library/src/main/java/com/evernote/android/state/StateSaverImpl.java @@ -14,8 +14,8 @@ import android.app.Application; import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import java.util.Map; diff --git a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListCharSequence.java b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListCharSequence.java index f23e66b..de9d1a6 100644 --- a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListCharSequence.java +++ b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListCharSequence.java @@ -11,8 +11,8 @@ package com.evernote.android.state.bundlers; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.evernote.android.state.Bundler; diff --git a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListInteger.java b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListInteger.java index c27f982..c9537ff 100644 --- a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListInteger.java +++ b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListInteger.java @@ -11,8 +11,8 @@ package com.evernote.android.state.bundlers; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.evernote.android.state.Bundler; diff --git a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListParcelable.java b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListParcelable.java index 7ee30fd..03bd0d4 100644 --- a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListParcelable.java +++ b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListParcelable.java @@ -12,8 +12,8 @@ import android.os.Bundle; import android.os.Parcelable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.evernote.android.state.Bundler; diff --git a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListString.java b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListString.java index 8433f0d..0103467 100644 --- a/library/src/main/java/com/evernote/android/state/bundlers/BundlerListString.java +++ b/library/src/main/java/com/evernote/android/state/bundlers/BundlerListString.java @@ -11,8 +11,8 @@ package com.evernote.android.state.bundlers; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.evernote.android.state.Bundler; diff --git a/library/src/test/java/com/evernote/android/state/test/TestBundler.java b/library/src/test/java/com/evernote/android/state/test/TestBundler.java index 4a564df..138dad2 100644 --- a/library/src/test/java/com/evernote/android/state/test/TestBundler.java +++ b/library/src/test/java/com/evernote/android/state/test/TestBundler.java @@ -1,8 +1,8 @@ package com.evernote.android.state.test; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.evernote.android.state.Bundler; import com.evernote.android.state.State; diff --git a/processor/build.gradle b/processor/build.gradle index 5cdfc4f..2cacc31 100644 --- a/processor/build.gradle +++ b/processor/build.gradle @@ -10,7 +10,7 @@ archivesBaseName = 'android-state-processor' compileJava.dependsOn ":library:bundleRelease" dependencies { - implementation 'com.squareup:javapoet:1.9.0' + implementation 'com.squareup:javapoet:1.11.0' implementation 'com.google.auto.service:auto-service:1.0-rc4' implementation 'com.google.android:android:4.1.1.4' From 4f9e3f30ac8521dfde5b40c887a482331cde60f3 Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 23 Sep 2018 19:37:54 -0700 Subject: [PATCH 10/18] Fix tests after sort order of fields has been changed --- .../evernote/android/state/TestProcessor.java | 124 +++++++++--------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/processor/src/test/java/com/evernote/android/state/TestProcessor.java b/processor/src/test/java/com/evernote/android/state/TestProcessor.java index 29c1b82..2814b60 100644 --- a/processor/src/test/java/com/evernote/android/state/TestProcessor.java +++ b/processor/src/test/java/com/evernote/android/state/TestProcessor.java @@ -700,85 +700,85 @@ public void testAllTypes() { + " @Override\n" + " @SuppressWarnings(\"unchecked\")\n" + " public void save(T target, Bundle state) {\n" - + " HELPER.putBundle(state, \"mBundle\", target.mBundle);\n" - + " HELPER.putParcelableArray(state, \"mParcelableArray\", target.mParcelableArray);\n" - + " HELPER.putSparseParcelableArray(state, \"mParcelableSparseArray\", target.mParcelableSparseArray);\n" + " HELPER.putBoolean(state, \"mBoolean\", target.mBoolean);\n" + " HELPER.putBooleanArray(state, \"mBooleanArray\", target.mBooleanArray);\n" + + " HELPER.putBoxedBoolean(state, \"mBooleanObj\", target.mBooleanObj);\n" + + " HELPER.putBundle(state, \"mBundle\", target.mBundle);\n" + " HELPER.putByte(state, \"mByte\", target.mByte);\n" + " HELPER.putByteArray(state, \"mByteArray\", target.mByteArray);\n" + + " HELPER.putBoxedByte(state, \"mByteObj\", target.mByteObj);\n" + " HELPER.putChar(state, \"mChar\", target.mChar);\n" + " HELPER.putCharArray(state, \"mCharArray\", target.mCharArray);\n" - + " HELPER.putParcelable(state, \"mParcelableImpl\", target.mParcelableImpl);\n" - + " HELPER.putSerializable(state, \"mSerializableImpl\", target.mSerializableImpl);\n" + + " HELPER.putBoxedChar(state, \"mCharObj\", target.mCharObj);\n" + + " HELPER.putCharSequence(state, \"mCharSequence\", target.mCharSequence);\n" + + " HELPER.putCharSequenceArray(state, \"mCharSequenceArray\", target.mCharSequenceArray);\n" + + " HELPER.putCharSequenceArrayList(state, \"mCharSequenceArrayList\", target.mCharSequenceArrayList);\n" + " HELPER.putDouble(state, \"mDouble\", target.mDouble);\n" + " HELPER.putDoubleArray(state, \"mDoubleArray\", target.mDoubleArray);\n" + + " HELPER.putBoxedDouble(state, \"mDoubleObj\", target.mDoubleObj);\n" + " HELPER.putFloat(state, \"mFloat\", target.mFloat);\n" + " HELPER.putFloatArray(state, \"mFloatArray\", target.mFloatArray);\n" + + " HELPER.putBoxedFloat(state, \"mFloatObj\", target.mFloatObj);\n" + " HELPER.putInt(state, \"mInt\", target.mInt);\n" + " HELPER.putIntArray(state, \"mIntArray\", target.mIntArray);\n" - + " HELPER.putBoxedBoolean(state, \"mBooleanObj\", target.mBooleanObj);\n" - + " HELPER.putBoxedByte(state, \"mByteObj\", target.mByteObj);\n" - + " HELPER.putCharSequence(state, \"mCharSequence\", target.mCharSequence);\n" - + " HELPER.putCharSequenceArray(state, \"mCharSequenceArray\", target.mCharSequenceArray);\n" - + " HELPER.putBoxedChar(state, \"mCharObj\", target.mCharObj);\n" - + " HELPER.putBoxedDouble(state, \"mDoubleObj\", target.mDoubleObj);\n" - + " HELPER.putBoxedFloat(state, \"mFloatObj\", target.mFloatObj);\n" + + " HELPER.putIntegerArrayList(state, \"mIntegerArrayList\", target.mIntegerArrayList);\n" + " HELPER.putBoxedInt(state, \"mIntegerObj\", target.mIntegerObj);\n" + + " HELPER.putLong(state, \"mLong\", target.mLong);\n" + + " HELPER.putLongArray(state, \"mLongArray\", target.mLongArray);\n" + " HELPER.putBoxedLong(state, \"mLongObj\", target.mLongObj);\n" + + " HELPER.putParcelableArray(state, \"mParcelableArray\", target.mParcelableArray);\n" + + " HELPER.putParcelableArrayList(state, \"mParcelableArrayList\", target.mParcelableArrayList);\n" + + " HELPER.putParcelable(state, \"mParcelableImpl\", target.mParcelableImpl);\n" + + " HELPER.putSparseParcelableArray(state, \"mParcelableSparseArray\", target.mParcelableSparseArray);\n" + + " HELPER.putSerializable(state, \"mSerializableImpl\", target.mSerializableImpl);\n" + + " HELPER.putShort(state, \"mShort\", target.mShort);\n" + + " HELPER.putShortArray(state, \"mShortArray\", target.mShortArray);\n" + " HELPER.putBoxedShort(state, \"mShortObj\", target.mShortObj);\n" + " HELPER.putString(state, \"mString\", target.mString);\n" + " HELPER.putStringArray(state, \"mStringArray\", target.mStringArray);\n" - + " HELPER.putParcelableArrayList(state, \"mParcelableArrayList\", target.mParcelableArrayList);\n" - + " HELPER.putCharSequenceArrayList(state, \"mCharSequenceArrayList\", target.mCharSequenceArrayList);\n" - + " HELPER.putIntegerArrayList(state, \"mIntegerArrayList\", target.mIntegerArrayList);\n" + " HELPER.putStringArrayList(state, \"mStringArrayList\", target.mStringArrayList);\n" - + " HELPER.putLong(state, \"mLong\", target.mLong);\n" - + " HELPER.putLongArray(state, \"mLongArray\", target.mLongArray);\n" - + " HELPER.putShort(state, \"mShort\", target.mShort);\n" - + " HELPER.putShortArray(state, \"mShortArray\", target.mShortArray);\n" + " }\n" + "\n" + " @Override\n" + " @SuppressWarnings(\"unchecked\")\n" + " public void restore(T target, Bundle state) {\n" - + " target.mBundle = HELPER.getBundle(state, \"mBundle\");\n" - + " target.mParcelableArray = HELPER.getParcelableArray(state, \"mParcelableArray\");\n" - + " target.mParcelableSparseArray = HELPER.getSparseParcelableArray(state, \"mParcelableSparseArray\");\n" + " target.mBoolean = HELPER.getBoolean(state, \"mBoolean\");\n" + " target.mBooleanArray = HELPER.getBooleanArray(state, \"mBooleanArray\");\n" + + " target.mBooleanObj = HELPER.getBoxedBoolean(state, \"mBooleanObj\");\n" + + " target.mBundle = HELPER.getBundle(state, \"mBundle\");\n" + " target.mByte = HELPER.getByte(state, \"mByte\");\n" + " target.mByteArray = HELPER.getByteArray(state, \"mByteArray\");\n" + + " target.mByteObj = HELPER.getBoxedByte(state, \"mByteObj\");\n" + " target.mChar = HELPER.getChar(state, \"mChar\");\n" + " target.mCharArray = HELPER.getCharArray(state, \"mCharArray\");\n" - + " target.mParcelableImpl = HELPER.getParcelable(state, \"mParcelableImpl\");\n" - + " target.mSerializableImpl = HELPER.getSerializable(state, \"mSerializableImpl\");\n" + + " target.mCharObj = HELPER.getBoxedChar(state, \"mCharObj\");\n" + + " target.mCharSequence = HELPER.getCharSequence(state, \"mCharSequence\");\n" + + " target.mCharSequenceArray = HELPER.getCharSequenceArray(state, \"mCharSequenceArray\");\n" + + " target.mCharSequenceArrayList = HELPER.getCharSequenceArrayList(state, \"mCharSequenceArrayList\");\n" + " target.mDouble = HELPER.getDouble(state, \"mDouble\");\n" + " target.mDoubleArray = HELPER.getDoubleArray(state, \"mDoubleArray\");\n" + + " target.mDoubleObj = HELPER.getBoxedDouble(state, \"mDoubleObj\");\n" + " target.mFloat = HELPER.getFloat(state, \"mFloat\");\n" + " target.mFloatArray = HELPER.getFloatArray(state, \"mFloatArray\");\n" + + " target.mFloatObj = HELPER.getBoxedFloat(state, \"mFloatObj\");\n" + " target.mInt = HELPER.getInt(state, \"mInt\");\n" + " target.mIntArray = HELPER.getIntArray(state, \"mIntArray\");\n" - + " target.mBooleanObj = HELPER.getBoxedBoolean(state, \"mBooleanObj\");\n" - + " target.mByteObj = HELPER.getBoxedByte(state, \"mByteObj\");\n" - + " target.mCharSequence = HELPER.getCharSequence(state, \"mCharSequence\");\n" - + " target.mCharSequenceArray = HELPER.getCharSequenceArray(state, \"mCharSequenceArray\");\n" - + " target.mCharObj = HELPER.getBoxedChar(state, \"mCharObj\");\n" - + " target.mDoubleObj = HELPER.getBoxedDouble(state, \"mDoubleObj\");\n" - + " target.mFloatObj = HELPER.getBoxedFloat(state, \"mFloatObj\");\n" + + " target.mIntegerArrayList = HELPER.getIntegerArrayList(state, \"mIntegerArrayList\");\n" + " target.mIntegerObj = HELPER.getBoxedInt(state, \"mIntegerObj\");\n" + + " target.mLong = HELPER.getLong(state, \"mLong\");\n" + + " target.mLongArray = HELPER.getLongArray(state, \"mLongArray\");\n" + " target.mLongObj = HELPER.getBoxedLong(state, \"mLongObj\");\n" + + " target.mParcelableArray = HELPER.getParcelableArray(state, \"mParcelableArray\");\n" + + " target.mParcelableArrayList = HELPER.getParcelableArrayList(state, \"mParcelableArrayList\");\n" + + " target.mParcelableImpl = HELPER.getParcelable(state, \"mParcelableImpl\");\n" + + " target.mParcelableSparseArray = HELPER.getSparseParcelableArray(state, \"mParcelableSparseArray\");\n" + + " target.mSerializableImpl = HELPER.getSerializable(state, \"mSerializableImpl\");\n" + + " target.mShort = HELPER.getShort(state, \"mShort\");\n" + + " target.mShortArray = HELPER.getShortArray(state, \"mShortArray\");\n" + " target.mShortObj = HELPER.getBoxedShort(state, \"mShortObj\");\n" + " target.mString = HELPER.getString(state, \"mString\");\n" + " target.mStringArray = HELPER.getStringArray(state, \"mStringArray\");\n" - + " target.mParcelableArrayList = HELPER.getParcelableArrayList(state, \"mParcelableArrayList\");\n" - + " target.mCharSequenceArrayList = HELPER.getCharSequenceArrayList(state, \"mCharSequenceArrayList\");\n" - + " target.mIntegerArrayList = HELPER.getIntegerArrayList(state, \"mIntegerArrayList\");\n" + " target.mStringArrayList = HELPER.getStringArrayList(state, \"mStringArrayList\");\n" - + " target.mLong = HELPER.getLong(state, \"mLong\");\n" - + " target.mLongArray = HELPER.getLongArray(state, \"mLongArray\");\n" - + " target.mShort = HELPER.getShort(state, \"mShort\");\n" - + " target.mShortArray = HELPER.getShortArray(state, \"mShortArray\");\n" + " }\n" + "}"); @@ -1051,12 +1051,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mParcelableArray\");\n" + + " Field field = target.getClass().getDeclaredField(\"mInt\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putParcelableArray(state, \"mParcelableArray\", (android.os.Parcelable[]) field.get(target));\n" + + " HELPER.putInt(state, \"mInt\", (int) field.getInt(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1064,12 +1064,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mParcelableSparseArray\");\n" + + " Field field = target.getClass().getDeclaredField(\"mIntArray\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putSparseParcelableArray(state, \"mParcelableSparseArray\", (android.util.SparseArray) field.get(target));\n" + + " HELPER.putIntArray(state, \"mIntArray\", (int[]) field.get(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1077,12 +1077,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mInt\");\n" + + " Field field = target.getClass().getDeclaredField(\"mIntegerObj\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putInt(state, \"mInt\", (int) field.getInt(target));\n" + + " HELPER.putBoxedInt(state, \"mIntegerObj\", (java.lang.Integer) field.get(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1090,12 +1090,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mIntArray\");\n" + + " Field field = target.getClass().getDeclaredField(\"mParcelableArray\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putIntArray(state, \"mIntArray\", (int[]) field.get(target));\n" + + " HELPER.putParcelableArray(state, \"mParcelableArray\", (android.os.Parcelable[]) field.get(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1103,12 +1103,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mIntegerObj\");\n" + + " Field field = target.getClass().getDeclaredField(\"mParcelableArrayList\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putBoxedInt(state, \"mIntegerObj\", (java.lang.Integer) field.get(target));\n" + + " HELPER.putSerializable(state, \"mParcelableArrayList\", (java.io.Serializable) field.get(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1116,12 +1116,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mParcelableArrayList\");\n" + + " Field field = target.getClass().getDeclaredField(\"mParcelableSparseArray\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " HELPER.putSerializable(state, \"mParcelableArrayList\", (java.io.Serializable) field.get(target));\n" + + " HELPER.putSparseParcelableArray(state, \"mParcelableSparseArray\", (android.util.SparseArray) field.get(target));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1147,12 +1147,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mParcelableArray\");\n" + + " Field field = target.getClass().getDeclaredField(\"mInt\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " field.set(target, HELPER.getParcelableArray(state, \"mParcelableArray\"));\n" + + " field.setInt(target, HELPER.getInt(state, \"mInt\"));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1160,12 +1160,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mParcelableSparseArray\");\n" + + " Field field = target.getClass().getDeclaredField(\"mIntArray\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " field.set(target, HELPER.getSparseParcelableArray(state, \"mParcelableSparseArray\"));\n" + + " field.set(target, HELPER.getIntArray(state, \"mIntArray\"));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1173,12 +1173,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mInt\");\n" + + " Field field = target.getClass().getDeclaredField(\"mIntegerObj\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " field.setInt(target, HELPER.getInt(state, \"mInt\"));\n" + + " field.set(target, HELPER.getBoxedInt(state, \"mIntegerObj\"));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1186,12 +1186,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mIntArray\");\n" + + " Field field = target.getClass().getDeclaredField(\"mParcelableArray\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " field.set(target, HELPER.getIntArray(state, \"mIntArray\"));\n" + + " field.set(target, HELPER.getParcelableArray(state, \"mParcelableArray\"));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1199,12 +1199,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mIntegerObj\");\n" + + " Field field = target.getClass().getDeclaredField(\"mParcelableArrayList\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " field.set(target, HELPER.getBoxedInt(state, \"mIntegerObj\"));\n" + + " field.set(target, HELPER.getSerializable(state, \"mParcelableArrayList\"));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" @@ -1212,12 +1212,12 @@ public void testReflection() { + " throw new RuntimeException(e);\n" + " }\n" + " try {\n" - + " Field field = target.getClass().getDeclaredField(\"mParcelableArrayList\");\n" + + " Field field = target.getClass().getDeclaredField(\"mParcelableSparseArray\");\n" + " boolean accessible = field.isAccessible();\n" + " if (!accessible) {\n" + " field.setAccessible(true);\n" + " }\n" - + " field.set(target, HELPER.getSerializable(state, \"mParcelableArrayList\"));\n" + + " field.set(target, HELPER.getSparseParcelableArray(state, \"mParcelableSparseArray\"));\n" + " if (!accessible) {\n" + " field.setAccessible(false);\n" + " }\n" From 4c4c46d583cdfeeb506b4901cb1d89b1d8f8894b Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 23 Sep 2018 20:00:45 -0700 Subject: [PATCH 11/18] Fix compile error with generic types and inner classes --- .../com/evernote/android/state/StateProcessor.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/processor/src/main/java/com/evernote/android/state/StateProcessor.java b/processor/src/main/java/com/evernote/android/state/StateProcessor.java index 3b3d633..3357b43 100644 --- a/processor/src/main/java/com/evernote/android/state/StateProcessor.java +++ b/processor/src/main/java/com/evernote/android/state/StateProcessor.java @@ -869,7 +869,16 @@ private static List sorted(Collection coll private TypeMirror eraseGenericIfNecessary(TypeMirror typeMirror) { // is there a better way to detect a generic type? - return (typeMirror.toString().endsWith(">")) ? mTypeUtils.erasure(typeMirror) : typeMirror; + String[] split = typeMirror.toString().split("\\."); + boolean hasGeneric = false; + for (String className : split) { + if (className.endsWith(">")) { + hasGeneric = true; + break; + } + } + + return hasGeneric ? mTypeUtils.erasure(typeMirror) : typeMirror; } private TypeMirror eraseCovarianceAndInvariance(TypeMirror typeMirror) { From 7fe39165ce39fb03c0b9c6da33562c2a99dcbfae Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 23 Sep 2018 20:04:16 -0700 Subject: [PATCH 12/18] Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89434e3..411581c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.4.0 (2018-09-23) + +* Migrated dependencies to AndroidX +* Sort elements by name to make processor deterministic, see #57 (Thanks @DSteve595) +* Fix compile error with generic inner classes and kapt, see #54 (Thanks @janbina) + ## 1.3.1 (2018-06-10) * Avoid obfuscating the class name if the class contains a field annotated with `@State`, see #43 From 1b1a6a9ba46aefb0094248741df063f59a28945d Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 23 Sep 2018 20:13:14 -0700 Subject: [PATCH 13/18] Publish version 1.4.0 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9ccce0e..22661a9 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ Download the latest [library](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%2 ```groovy dependencies { - implementation 'com.evernote:android-state:1.3.1' + implementation 'com.evernote:android-state:1.4.0' // Java only project - annotationProcessor 'com.evernote:android-state-processor:1.3.1' + annotationProcessor 'com.evernote:android-state-processor:1.4.0' // Kotlin with or without Java - kapt 'com.evernote:android-state-processor:1.3.1' + kapt 'com.evernote:android-state-processor:1.4.0' } ``` From a62e6fa8edde48de70d5b1dbc952911d315c6463 Mon Sep 17 00:00:00 2001 From: floynn Date: Wed, 3 Oct 2018 10:39:10 -0700 Subject: [PATCH 14/18] Update android dependency to compileOnly --- processor/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/processor/build.gradle b/processor/build.gradle index 2cacc31..cf20200 100644 --- a/processor/build.gradle +++ b/processor/build.gradle @@ -13,7 +13,7 @@ dependencies { implementation 'com.squareup:javapoet:1.11.0' implementation 'com.google.auto.service:auto-service:1.0-rc4' - implementation 'com.google.android:android:4.1.1.4' + compileOnly 'com.google.android:android:4.1.1.4' implementation files('../library/build/intermediates/packaged-classes/release/classes.jar') From 028d662be75a95de73129ac680bc995d26a282f0 Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sat, 6 Oct 2018 15:58:33 -0700 Subject: [PATCH 15/18] Upgrade dependencies --- build.gradle | 6 +++--- processor/build.gradle | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 78cd5b7..c555e11 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { - ext.kotlinVersion = '1.2.70' - ext.agpVersion = '3.1.4' + ext.kotlinVersion = '1.2.71' + ext.agpVersion = '3.2.0' repositories { google() @@ -31,7 +31,7 @@ ext { targetSdkVersion = compileSdkVersion minSdkVersion = 14 - buildToolsVersion = '28.0.2' + buildToolsVersion = '28.0.3' junitVersion = '4.12' assertjVersion = '3.6.2' diff --git a/processor/build.gradle b/processor/build.gradle index cf20200..4cc750f 100644 --- a/processor/build.gradle +++ b/processor/build.gradle @@ -7,10 +7,10 @@ targetCompatibility = JavaVersion.VERSION_1_7 archivesBaseName = 'android-state-processor' -compileJava.dependsOn ":library:bundleRelease" +compileJava.dependsOn ":library:bundleReleaseAar" dependencies { - implementation 'com.squareup:javapoet:1.11.0' + implementation 'com.squareup:javapoet:1.11.1' implementation 'com.google.auto.service:auto-service:1.0-rc4' compileOnly 'com.google.android:android:4.1.1.4' From 09892ab355a39c45d0191f51added7b1dba28080 Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sat, 6 Oct 2018 18:50:21 -0700 Subject: [PATCH 16/18] Remove Android dependency from processor, this resolves problems with the Jetifier, see #56 --- CHANGELOG.md | 4 + processor/build.gradle | 12 +-- .../android/state/StateProcessor.java | 99 +++++++++++-------- .../evernote/android/state/TestProcessor.java | 2 +- 4 files changed, 65 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 411581c..86e6823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.4.1 (2018-09-23) + +* Remove Android dependency from processor, this resolves problems with the Jetifier, see #56 + ## 1.4.0 (2018-09-23) * Migrated dependencies to AndroidX diff --git a/processor/build.gradle b/processor/build.gradle index 4cc750f..9b70d1b 100644 --- a/processor/build.gradle +++ b/processor/build.gradle @@ -7,15 +7,15 @@ targetCompatibility = JavaVersion.VERSION_1_7 archivesBaseName = 'android-state-processor' -compileJava.dependsOn ":library:bundleReleaseAar" +test.dependsOn ":library:bundleReleaseAar" dependencies { implementation 'com.squareup:javapoet:1.11.1' - implementation 'com.google.auto.service:auto-service:1.0-rc4' - compileOnly 'com.google.android:android:4.1.1.4' + compileOnly 'com.google.auto.service:auto-service:1.0-rc4' - implementation files('../library/build/intermediates/packaged-classes/release/classes.jar') + testImplementation 'com.google.android:android:4.1.1.4' + testImplementation files('../library/build/intermediates/packaged-classes/release/classes.jar') testImplementation "junit:junit:$junitVersion" testImplementation 'com.google.testing.compile:compile-testing:0.15' @@ -24,10 +24,6 @@ dependencies { jar { destinationDir = new File("$project.buildDir/outputs/jar/") - - from ('../library/build/intermediates/classes/release') { - include 'com/evernote/android/**' - } } apply from: "$rootDir/gradle/gradle-push.gradle" \ No newline at end of file diff --git a/processor/src/main/java/com/evernote/android/state/StateProcessor.java b/processor/src/main/java/com/evernote/android/state/StateProcessor.java index 3357b43..d05ee55 100644 --- a/processor/src/main/java/com/evernote/android/state/StateProcessor.java +++ b/processor/src/main/java/com/evernote/android/state/StateProcessor.java @@ -10,11 +10,6 @@ *******************************************************************************/ package com.evernote.android.state; -import android.os.Bundle; -import android.os.Parcelable; -import android.util.SparseArray; -import android.view.View; - import com.google.auto.service.AutoService; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; @@ -115,12 +110,23 @@ public int compare(Element o1, Element o2) { } }; - private static final String STATE_CLASS_NAME = State.class.getName(); - private static final String STATE_REFLECTION_CLASS_NAME = StateReflection.class.getName(); + /*package*/ static final String STATE_SAVER_SUFFIX = "$$StateSaver"; + + private static final String STATE_CLASS_NAME = "com.evernote.android.state.State"; + private static final String STATE_REFLECTION_CLASS_NAME = "com.evernote.android.state.StateReflection"; + private static final String INJECTOR_VIEW_CLASS_NAME = "com.evernote.android.state.Injector.View"; + private static final String INJECTOR_OBJECT_CLASS_NAME = "com.evernote.android.state.Injector.Object"; + private static final String INJECTION_HELPER_CLASS_NAME = "com.evernote.android.state.InjectionHelper"; + private static final String OBJECT_CLASS_NAME = Object.class.getName(); - private static final String PARCELABLE_CLASS_NAME = Parcelable.class.getName(); - private static final String PARCELABLE_ARRAY_CLASS_NAME = Parcelable[].class.getCanonicalName(); + private static final String PARCELABLE_CLASS_NAME = "android.os.Parcelable"; + private static final String PARCELABLE_ARRAY_CLASS_NAME = "android.os.Parcelable[]"; + private static final String BUNDLE_CLASS_NAME = "android.os.Bundle"; + private static final String SPARSE_ARRAY_CLASS_NAME = "android.util.SparseArray"; + private static final String VIEW_CLASS_NAME = "android.view.View"; + private static final String BUNDLER_CLASS_NAME = "com.evernote.android.state.Bundler"; private static final String SERIALIZABLE_CLASS_NAME = Serializable.class.getName(); + private static final String ARRAY_LIST_CLASS_NAME = ArrayList.class.getName(); private static final Set GENERIC_SUPER_TYPES = Collections.unmodifiableSet(new HashSet() {{ add(PARCELABLE_CLASS_NAME); @@ -130,7 +136,7 @@ public int compare(Element o1, Element o2) { private static final Set GENERIC_SUPER_TYPE_SERIALIZABLE = Collections.singleton(SERIALIZABLE_CLASS_NAME); private static final Set IGNORED_TYPE_DECLARATIONS = Collections.unmodifiableSet(new HashSet() {{ - add(Bundle.class.getName()); + add(BUNDLE_CLASS_NAME); add(String.class.getName()); add(Byte.class.getName()); add(Short.class.getName()); @@ -161,8 +167,8 @@ public synchronized void init(ProcessingEnvironment processingEnv) { @Override public Set getSupportedAnnotationTypes() { Set annotations = new HashSet<>(); - annotations.add(State.class.getName()); - annotations.add(StateReflection.class.getName()); + annotations.add(STATE_CLASS_NAME); + annotations.add(STATE_REFLECTION_CLASS_NAME); return Collections.unmodifiableSet(annotations); } @@ -174,8 +180,8 @@ public SourceVersion getSupportedSourceVersion() { @Override public boolean process(Set annotations, RoundEnvironment env) { final Set annotatedFields = new HashSet<>(); - annotatedFields.addAll(env.getElementsAnnotatedWith(State.class)); - annotatedFields.addAll(env.getElementsAnnotatedWith(StateReflection.class)); + annotatedFields.addAll(env.getElementsAnnotatedWith(mElementUtils.getTypeElement(STATE_CLASS_NAME))); + annotatedFields.addAll(env.getElementsAnnotatedWith(mElementUtils.getTypeElement(STATE_REFLECTION_CLASS_NAME))); final Map bundlers = new HashMap<>(); @@ -247,16 +253,16 @@ public boolean process(Set annotations, RoundEnvironment } final String className = getClassName(classElement); - final boolean isView = isAssignable(classElement, View.class); + final boolean isView = isAssignable(classElement, VIEW_CLASS_NAME); final TypeVariableName genericType = TypeVariableName.get("T", TypeName.get(eraseGenericIfNecessary(classElement.asType()))); final TypeName superTypeName; final TypeMirror superType = getSuperType(classElement.asType(), allClassElements); if (superType == null) { - superTypeName = ParameterizedTypeName.get(ClassName.get(isView ? Injector.View.class : Injector.Object.class), genericType); + superTypeName = ParameterizedTypeName.get(ClassName.bestGuess(isView ? INJECTOR_VIEW_CLASS_NAME : INJECTOR_OBJECT_CLASS_NAME), genericType); } else { - ClassName rawType = ClassName.bestGuess(eraseGenericIfNecessary(superType).toString() + StateSaver.SUFFIX); + ClassName rawType = ClassName.bestGuess(eraseGenericIfNecessary(superType).toString() + STATE_SAVER_SUFFIX); if (!rawType.toString().equals(rawType.reflectionName())) { rawType = ClassName.bestGuess(rawType.reflectionName()); } @@ -285,20 +291,23 @@ public boolean process(Set annotations, RoundEnvironment .addModifiers(Modifier.PUBLIC) .addParameter(genericType, "target"); + TypeName bundleTypeName = getTypeName(BUNDLE_CLASS_NAME); if (isView) { - saveMethodBuilder = saveMethodBuilder.returns(Parcelable.class).addParameter(Parcelable.class, "p"); - restoreMethodBuilder = restoreMethodBuilder.returns(Parcelable.class).addParameter(Parcelable.class, "p"); + TypeName parcelableTypeName = getTypeName(PARCELABLE_CLASS_NAME); + + saveMethodBuilder = saveMethodBuilder.returns(parcelableTypeName).addParameter(parcelableTypeName, "p"); + restoreMethodBuilder = restoreMethodBuilder.returns(parcelableTypeName).addParameter(parcelableTypeName, "p"); if (superType != null) { - saveMethodBuilder = saveMethodBuilder.addStatement("$T state = HELPER.putParent(super.save(target, p))", Bundle.class); + saveMethodBuilder = saveMethodBuilder.addStatement("$T state = HELPER.putParent(super.save(target, p))", bundleTypeName); } else { - saveMethodBuilder = saveMethodBuilder.addStatement("$T state = HELPER.putParent(p)", Bundle.class); + saveMethodBuilder = saveMethodBuilder.addStatement("$T state = HELPER.putParent(p)", bundleTypeName); } - restoreMethodBuilder = restoreMethodBuilder.addStatement("$T state = ($T) p", Bundle.class, Bundle.class); + restoreMethodBuilder = restoreMethodBuilder.addStatement("$T state = ($T) p", bundleTypeName, bundleTypeName); } else { - saveMethodBuilder = saveMethodBuilder.returns(void.class).addParameter(Bundle.class, "state"); - restoreMethodBuilder = restoreMethodBuilder.returns(void.class).addParameter(Bundle.class, "state"); + saveMethodBuilder = saveMethodBuilder.returns(void.class).addParameter(bundleTypeName, "state"); + restoreMethodBuilder = restoreMethodBuilder.returns(void.class).addParameter(bundleTypeName, "state"); if (superType != null) { saveMethodBuilder = saveMethodBuilder.addStatement("super.save(target, state)"); @@ -385,7 +394,7 @@ public boolean process(Set annotations, RoundEnvironment InsertedTypeResult insertedType = getInsertedType(field, true); if (compatibilityType != null && insertedType != null) { // either serializable or parcelable, this could be a private inner class, so don't use the concrete type - fieldTypeString = compatibilityType.mClass.getName(); + fieldTypeString = compatibilityType.mClass; } saveMethodBuilder = saveMethodBuilder @@ -436,10 +445,10 @@ public boolean process(Set annotations, RoundEnvironment } } - TypeName bundlerType = ParameterizedTypeName.get(ClassName.get(Bundler.class), WildcardTypeName.subtypeOf(Object.class)); + TypeName bundlerType = ParameterizedTypeName.get(ClassName.bestGuess(BUNDLER_CLASS_NAME), WildcardTypeName.subtypeOf(Object.class)); TypeName bundlerMap = ParameterizedTypeName.get(ClassName.get(HashMap.class), ClassName.get(String.class), bundlerType); - TypeSpec classBuilder = TypeSpec.classBuilder(className + StateSaver.SUFFIX) + TypeSpec classBuilder = TypeSpec.classBuilder(className + STATE_SAVER_SUFFIX) .addModifiers(Modifier.PUBLIC) .superclass(superTypeName) .addTypeVariable(genericType) @@ -451,9 +460,9 @@ public boolean process(Set annotations, RoundEnvironment ) .addStaticBlock(staticInitBlock.build()) .addField( - FieldSpec.builder(InjectionHelper.class, "HELPER") + FieldSpec.builder(getTypeName(INJECTION_HELPER_CLASS_NAME), "HELPER") .addModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE) - .initializer("new $T($S, $N)", InjectionHelper.class, packageName + '.' + className + StateSaver.SUFFIX, "BUNDLERS") + .initializer("new $T($S, $N)", getTypeName(INJECTION_HELPER_CLASS_NAME), packageName + '.' + className + STATE_SAVER_SUFFIX, "BUNDLERS") .build() ) .addMethod(saveMethodBuilder.build()) @@ -728,7 +737,7 @@ private BundlerWrapper getBundlerWrapper(Element field) { // gets the generic type Data from `class MyBundler implements Bundler {}` List interfaces = mElementUtils.getTypeElement(value.toString()).getInterfaces(); for (TypeMirror anInterface : interfaces) { - if (isAssignable(mTypeUtils.erasure(anInterface), Bundler.class)) { + if (isAssignable(mTypeUtils.erasure(anInterface), BUNDLER_CLASS_NAME)) { List typeArguments = ((DeclaredType) anInterface).getTypeArguments(); if (typeArguments != null && typeArguments.size() >= 1) { TypeMirror genericTypeMirror = typeArguments.get(0); @@ -800,17 +809,17 @@ private BundlerWrapper(TypeName bundlerName, TypeName genericName) { @SuppressWarnings("unused") private enum CompatibilityType { - PARCELABLE("Parcelable", Parcelable.class, null), - PARCELABLE_ARRAY("ParcelableArray", Parcelable[].class, null), - PARCELABLE_LIST("ParcelableArrayList", ArrayList.class, Parcelable.class), - SPARSE_PARCELABLE_ARRAY("SparseParcelableArray", SparseArray.class, Parcelable.class), - SERIALIZABLE("Serializable", Serializable.class, null); + PARCELABLE("Parcelable", PARCELABLE_CLASS_NAME, null), + PARCELABLE_ARRAY("ParcelableArray", PARCELABLE_ARRAY_CLASS_NAME, null), + PARCELABLE_LIST("ParcelableArrayList", ARRAY_LIST_CLASS_NAME, PARCELABLE_CLASS_NAME), + SPARSE_PARCELABLE_ARRAY("SparseParcelableArray", SPARSE_ARRAY_CLASS_NAME, PARCELABLE_CLASS_NAME), + SERIALIZABLE("Serializable", SERIALIZABLE_CLASS_NAME, null); final String mMapping; - final Class mClass; - final Class mGenericClass; + final String mClass; + final String mGenericClass; - CompatibilityType(String mapping, Class clazz, Class genericClass) { + CompatibilityType(String mapping, String clazz, String genericClass) { mMapping = mapping; mClass = clazz; mGenericClass = genericClass; @@ -822,7 +831,7 @@ private CompatibilityType getCompatibilityType(Element field) { for (CompatibilityType compatibilityType : CompatibilityType.values()) { if (compatibilityType == CompatibilityType.PARCELABLE_ARRAY) { TypeMirror arrayType = getArrayType(field); - if (arrayType != null && isAssignable(arrayType, Parcelable.class)) { + if (arrayType != null && isAssignable(arrayType, PARCELABLE_CLASS_NAME)) { return CompatibilityType.PARCELABLE_ARRAY; } @@ -853,12 +862,12 @@ private TypeMirror getArrayType(Element field) { } @SuppressWarnings("SameParameterValue") - private boolean isAssignable(Element element, Class clazz) { - return isAssignable(element.asType(), clazz); + private boolean isAssignable(Element element, String className) { + return isAssignable(element.asType(), className); } - private boolean isAssignable(TypeMirror typeMirror, Class clazz) { - return mTypeUtils.isAssignable(typeMirror, mElementUtils.getTypeElement(clazz.getName()).asType()); + private boolean isAssignable(TypeMirror typeMirror, String className) { + return mTypeUtils.isAssignable(typeMirror, mElementUtils.getTypeElement(className).asType()); } private static List sorted(Collection collection) { @@ -978,6 +987,10 @@ private boolean isStateAnnotation(AnnotationMirror annotationMirror) { return STATE_CLASS_NAME.equals(string) || STATE_REFLECTION_CLASS_NAME.equals(string); } + private TypeName getTypeName(String className) { + return TypeName.get(mElementUtils.getTypeElement(className).asType()); + } + private static final class InsertedTypeResult { private final TypeMirror mTypeMirror; private final boolean mSerializable; diff --git a/processor/src/test/java/com/evernote/android/state/TestProcessor.java b/processor/src/test/java/com/evernote/android/state/TestProcessor.java index 2814b60..48ca3ff 100644 --- a/processor/src/test/java/com/evernote/android/state/TestProcessor.java +++ b/processor/src/test/java/com/evernote/android/state/TestProcessor.java @@ -40,7 +40,7 @@ private static String getName(String className) { } private static String getName(String className, boolean addSuffix) { - return PACKAGE + className + (addSuffix ? StateSaver.SUFFIX : ""); + return PACKAGE + className + (addSuffix ? StateProcessor.STATE_SAVER_SUFFIX : ""); } @Test From 6d56c0c5709f330324ec23d39c3f70c9d59bf6d3 Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sat, 6 Oct 2018 18:53:39 -0700 Subject: [PATCH 17/18] Publish version 1.4.1 --- CHANGELOG.md | 2 +- README.md | 6 +++--- gradle.properties | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86e6823..d160847 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.4.1 (2018-09-23) +## 1.4.1 (2018-10-06) * Remove Android dependency from processor, this resolves problems with the Jetifier, see #56 diff --git a/README.md b/README.md index 22661a9..4d2cab5 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ Download the latest [library](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%2 ```groovy dependencies { - implementation 'com.evernote:android-state:1.4.0' + implementation 'com.evernote:android-state:1.4.1' // Java only project - annotationProcessor 'com.evernote:android-state-processor:1.4.0' + annotationProcessor 'com.evernote:android-state-processor:1.4.1' // Kotlin with or without Java - kapt 'com.evernote:android-state-processor:1.4.0' + kapt 'com.evernote:android-state-processor:1.4.1' } ``` diff --git a/gradle.properties b/gradle.properties index b980f1e..704f60f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -#VERSION_NAME=1.4.0 -VERSION_NAME=1.4.0-SNAPSHOT +#VERSION_NAME=1.4.1 +VERSION_NAME=1.4.1-SNAPSHOT VERSION_CODE=1 \ No newline at end of file From 79552ddcd89cdb80fa6372ecf75471a150cffabc Mon Sep 17 00:00:00 2001 From: Ralf Wondratschek Date: Sun, 29 Sep 2019 15:09:25 -0700 Subject: [PATCH 18/18] Deprecate library --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d2cab5..8de588a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -# Android-State +# DEPRECATED + +This library is not maintained anymore. + +# ~~Android-State~~ A utility library for Android to save objects in a `Bundle` without any boilerplate. It uses an annotation processor to wire up all dependencies.