diff options
author | Eugene Susla <eugenesusla@google.com> | 2019-10-03 17:22:44 -0700 |
---|---|---|
committer | Eugene Susla <eugenesusla@google.com> | 2019-10-04 16:18:48 -0700 |
commit | 8cb1a417142e3694e50b004bcd054abd6ecff541 (patch) | |
tree | 8e6fa1f4a0656be2061ce66d695ea3e0194b60e0 | |
parent | 2f49522757f6d587bc8fc2b81e60544196f29fec (diff) |
Add inheritance support for parcelable dataclasses
We don't want to recommend this, but some legacy framework classes use
inheritance, and it's easy enough to support
Fixes: 142081378
Test: . frameworks/base/tests/Codegen/runTest.sh
Change-Id: Ifb7f34abf1dfb871ac01b9a9a38dfee144e5f49a
13 files changed, 600 insertions, 194 deletions
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh index 01522735ec3c..bb3f5b257897 100755 --- a/tests/Codegen/runTest.sh +++ b/tests/Codegen/runTest.sh @@ -14,6 +14,8 @@ else header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java && \ header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java && \ + header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java && \ + header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java && \ cd $ANDROID_BUILD_TOP && header_and_eval mmma -j16 frameworks/base/tests/Codegen && \ header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \ diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.aidl b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.aidl new file mode 100644 index 000000000000..ab62c83fc1b9 --- /dev/null +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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.android.codegentest; + +parcelable HierrarchicalDataClassBase; diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java new file mode 100644 index 000000000000..9e9ddae4ca76 --- /dev/null +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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.android.codegentest; + +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * @see HierrarchicalDataClassChild + */ +@DataClass( + genConstructor = false, + genSetters = true) +public class HierrarchicalDataClassBase implements Parcelable { + + private int mBaseData; + + + + // Code below generated by codegen v1.0.5. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java + + + @DataClass.Generated.Member + public int getBaseData() { + return mBaseData; + } + + @DataClass.Generated.Member + public HierrarchicalDataClassBase setBaseData(int value) { + mBaseData = value; + return this; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mBaseData); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected HierrarchicalDataClassBase(android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int baseData = in.readInt(); + + this.mBaseData = baseData; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @android.annotation.NonNull Parcelable.Creator<HierrarchicalDataClassBase> CREATOR + = new Parcelable.Creator<HierrarchicalDataClassBase>() { + @Override + public HierrarchicalDataClassBase[] newArray(int size) { + return new HierrarchicalDataClassBase[size]; + } + + @Override + public HierrarchicalDataClassBase createFromParcel(android.os.Parcel in) { + return new HierrarchicalDataClassBase(in); + } + }; + + @DataClass.Generated( + time = 1570231100269L, + codegenVersion = "1.0.5", + sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java", + inputSignatures = "private int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)") + @Deprecated + private void __metadata() {} + +} diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.aidl b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.aidl new file mode 100644 index 000000000000..a0997222b0af --- /dev/null +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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.android.codegentest; + +parcelable HierrarchicalDataClassChild; diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java new file mode 100644 index 000000000000..27a6933d25e8 --- /dev/null +++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * 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.android.codegentest; + +import android.annotation.NonNull; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * An example of data classes that extend one another. + * + * Note that some features like constructor generation might not work well due to lack of + * information about the superclass when generating code for subclass. + * + * It is recommended to avoid inheritance in favor of composition for new data classes, + * particularly parcelable ones. + * + * However for legacy classes or where inheritance is desired for allocation efficiency, + * you can either use a technique from this example, opting for mutability/setters, or just write + * constructors by hand. + * + * @see HierrarchicalDataClassBase + */ +@DataClass( + genParcelable = true, + genConstructor = false, + genSetters = true) +public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase { + + private @NonNull String mChildData; + + + + // Code below generated by codegen v1.0.5. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java + + + @DataClass.Generated.Member + public @NonNull String getChildData() { + return mChildData; + } + + @DataClass.Generated.Member + public HierrarchicalDataClassChild setChildData(@NonNull String value) { + mChildData = value; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mChildData); + return this; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + super.writeToParcel(dest, flags); + + dest.writeString(mChildData); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected HierrarchicalDataClassChild(android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + super(in); + + String childData = in.readString(); + + this.mChildData = childData; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mChildData); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<HierrarchicalDataClassChild> CREATOR + = new Parcelable.Creator<HierrarchicalDataClassChild>() { + @Override + public HierrarchicalDataClassChild[] newArray(int size) { + return new HierrarchicalDataClassChild[size]; + } + + @Override + public HierrarchicalDataClassChild createFromParcel(android.os.Parcel in) { + return new HierrarchicalDataClassChild(in); + } + }; + + @DataClass.Generated( + time = 1570231101208L, + codegenVersion = "1.0.5", + sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java", + inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)") + @Deprecated + private void __metadata() {} + +} diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java index 2d4125783990..dafece17b7ac 100644 --- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java @@ -48,7 +48,7 @@ public class ParcelAllTheThingsDataClass implements Parcelable { - // Code below generated by codegen v1.0.4. + // Code below generated by codegen v1.0.5. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -162,6 +162,49 @@ public class ParcelAllTheThingsDataClass implements Parcelable { @DataClass.Generated.Member public int describeContents() { return 0; } + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected ParcelAllTheThingsDataClass(Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String[] stringArray = in.createStringArray(); + int[] intArray = in.createIntArray(); + List<String> stringList = new java.util.ArrayList<>(); + in.readStringList(stringList); + Map<String,SampleWithCustomBuilder> map = new java.util.LinkedHashMap<>(); + in.readMap(map, SampleWithCustomBuilder.class.getClassLoader()); + Map<String,String> stringMap = new java.util.LinkedHashMap<>(); + in.readMap(stringMap, String.class.getClassLoader()); + SparseArray<SampleWithCustomBuilder> sparseArray = (SparseArray) in.readSparseArray(SampleWithCustomBuilder.class.getClassLoader()); + SparseIntArray sparseIntArray = (SparseIntArray) in.readSparseIntArray(); + + this.mStringArray = stringArray; + AnnotationValidations.validate( + NonNull.class, null, mStringArray); + this.mIntArray = intArray; + AnnotationValidations.validate( + NonNull.class, null, mIntArray); + this.mStringList = stringList; + AnnotationValidations.validate( + NonNull.class, null, mStringList); + this.mMap = map; + AnnotationValidations.validate( + NonNull.class, null, mMap); + this.mStringMap = stringMap; + AnnotationValidations.validate( + NonNull.class, null, mStringMap); + this.mSparseArray = sparseArray; + AnnotationValidations.validate( + NonNull.class, null, mSparseArray); + this.mSparseIntArray = sparseIntArray; + AnnotationValidations.validate( + NonNull.class, null, mSparseIntArray); + + // onConstructed(); // You can define this method to get a callback + } + @DataClass.Generated.Member public static final @NonNull Parcelable.Creator<ParcelAllTheThingsDataClass> CREATOR = new Parcelable.Creator<ParcelAllTheThingsDataClass>() { @@ -171,29 +214,8 @@ public class ParcelAllTheThingsDataClass implements Parcelable { } @Override - @SuppressWarnings({"unchecked", "RedundantCast"}) public ParcelAllTheThingsDataClass createFromParcel(Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - String[] stringArray = in.createStringArray(); - int[] intArray = in.createIntArray(); - List<String> stringList = new java.util.ArrayList<>(); - in.readStringList(stringList); - Map<String,SampleWithCustomBuilder> map = new java.util.LinkedHashMap<>(); - in.readMap(map, SampleWithCustomBuilder.class.getClassLoader()); - Map<String,String> stringMap = new java.util.LinkedHashMap<>(); - in.readMap(stringMap, String.class.getClassLoader()); - SparseArray<SampleWithCustomBuilder> sparseArray = (SparseArray) in.readSparseArray(SampleWithCustomBuilder.class.getClassLoader()); - SparseIntArray sparseIntArray = (SparseIntArray) in.readSparseIntArray(); - return new ParcelAllTheThingsDataClass( - stringArray, - intArray, - stringList, - map, - stringMap, - sparseArray, - sparseIntArray); + return new ParcelAllTheThingsDataClass(in); } }; @@ -352,8 +374,8 @@ public class ParcelAllTheThingsDataClass implements Parcelable { } @DataClass.Generated( - time = 1570139502128L, - codegenVersion = "1.0.4", + time = 1570231099316L, + codegenVersion = "1.0.5", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java", inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java index 0631f7ded8ae..1d737361da6f 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java +++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java @@ -342,7 +342,7 @@ public final class SampleDataClass implements Parcelable { - // Code below generated by codegen v1.0.4. + // Code below generated by codegen v1.0.5. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -1290,6 +1290,123 @@ public final class SampleDataClass implements Parcelable { @DataClass.Generated.Member public int describeContents() { return 0; } + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ SampleDataClass(Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + long flg = in.readLong(); + int num = in.readInt(); + int num2 = in.readInt(); + int num4 = in.readInt(); + String name = (flg & 0x8) == 0 ? null : in.readString(); + String name2 = in.readString(); + String name4 = in.readString(); + AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR); + Date date = sParcellingForDate.unparcel(in); + Pattern pattern = sParcellingForPattern.unparcel(in); + List<LinkAddress> linkAddresses2 = new ArrayList<>(); + in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader()); + ArrayList<LinkAddress> linkAddresses = new ArrayList<>(); + in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader()); + LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR); + String stateName = in.readString(); + int flags = in.readInt(); + int state = in.readInt(); + CharSequence _charSeq = (CharSequence) in.readCharSequence(); + LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR); + int stringRes = in.readInt(); + int dayOfWeek = in.readInt(); + float[] coords = in.createFloatArray(); + + this.mNum = num; + this.mNum2 = num2; + this.mNum4 = num4; + this.mName = name; + this.mName2 = name2; + AnnotationValidations.validate( + NonNull.class, null, mName2); + this.mName4 = name4; + AnnotationValidations.validate( + NonNull.class, null, mName4); + this.mOtherParcelable = otherParcelable; + this.mDate = date; + AnnotationValidations.validate( + NonNull.class, null, mDate); + this.mPattern = pattern; + AnnotationValidations.validate( + NonNull.class, null, mPattern); + this.mLinkAddresses2 = linkAddresses2; + AnnotationValidations.validate( + NonNull.class, null, mLinkAddresses2); + this.mLinkAddresses = linkAddresses; + AnnotationValidations.validate( + NonNull.class, null, mLinkAddresses); + this.mLinkAddresses4 = linkAddresses4; + this.mStateName = stateName; + + if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED)) + && !(Objects.equals(mStateName, STATE_NAME_ON)) + && !(Objects.equals(mStateName, STATE_NAME_OFF))) { + throw new java.lang.IllegalArgumentException( + "stateName was " + mStateName + " but must be one of: " + + "STATE_NAME_UNDEFINED(" + STATE_NAME_UNDEFINED + "), " + + "STATE_NAME_ON(" + STATE_NAME_ON + "), " + + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")"); + } + + AnnotationValidations.validate( + NonNull.class, null, mStateName); + this.mFlags = flags; + + Preconditions.checkFlagsArgument( + mFlags, + FLAG_MANUAL_REQUEST + | FLAG_COMPATIBILITY_MODE_REQUEST + | FLAG_AUGMENTED_REQUEST); + this.mState = state; + + if (!(mState == STATE_UNDEFINED) + && !(mState == STATE_ON) + && !(mState == STATE_OFF)) { + throw new java.lang.IllegalArgumentException( + "state was " + mState + " but must be one of: " + + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), " + + "STATE_ON(" + STATE_ON + "), " + + "STATE_OFF(" + STATE_OFF + ")"); + } + + this.charSeq = _charSeq; + AnnotationValidations.validate( + NonNull.class, null, charSeq); + this.mLinkAddresses5 = linkAddresses5; + this.mStringRes = stringRes; + AnnotationValidations.validate( + StringRes.class, null, mStringRes); + this.mDayOfWeek = dayOfWeek; + AnnotationValidations.validate( + android.annotation.IntRange.class, null, mDayOfWeek, + "from", 0, + "to", 6); + this.mCoords = coords; + AnnotationValidations.validate( + Size.class, null, mCoords.length, + "value", 2); + AnnotationValidations.validate( + NonNull.class, null, mCoords); + int coordsSize = mCoords.length; + for (int i = 0; i < coordsSize; i++) { + AnnotationValidations.validate( + FloatRange.class, null, mCoords[i], + "from", 0f); + } + + + onConstructed(); + } + @DataClass.Generated.Member public static final @NonNull Parcelable.Creator<SampleDataClass> CREATOR = new Parcelable.Creator<SampleDataClass>() { @@ -1299,55 +1416,8 @@ public final class SampleDataClass implements Parcelable { } @Override - @SuppressWarnings({"unchecked", "RedundantCast"}) public SampleDataClass createFromParcel(Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - long flg = in.readLong(); - int num = in.readInt(); - int num2 = in.readInt(); - int num4 = in.readInt(); - String name = (flg & 0x8) == 0 ? null : in.readString(); - String name2 = in.readString(); - String name4 = in.readString(); - AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR); - Date date = sParcellingForDate.unparcel(in); - Pattern pattern = sParcellingForPattern.unparcel(in); - List<LinkAddress> linkAddresses2 = new ArrayList<>(); - in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader()); - ArrayList<LinkAddress> linkAddresses = new ArrayList<>(); - in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader()); - LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR); - String stateName = in.readString(); - int flags = in.readInt(); - int state = in.readInt(); - CharSequence _charSeq = (CharSequence) in.readCharSequence(); - LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR); - int stringRes = in.readInt(); - int dayOfWeek = in.readInt(); - float[] coords = in.createFloatArray(); - return new SampleDataClass( - num, - num2, - num4, - name, - name2, - name4, - otherParcelable, - date, - pattern, - linkAddresses2, - linkAddresses, - linkAddresses4, - stateName, - flags, - state, - _charSeq, - linkAddresses5, - stringRes, - dayOfWeek, - coords); + return new SampleDataClass(in); } }; @@ -1798,8 +1868,8 @@ public final class SampleDataClass implements Parcelable { } @DataClass.Generated( - time = 1570139500112L, - codegenVersion = "1.0.4", + time = 1570231097226L, + codegenVersion = "1.0.5", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java", inputSignatures = "public static final java.lang.String STATE_NAME_UNDEFINED\npublic static final java.lang.String STATE_NAME_ON\npublic static final java.lang.String STATE_NAME_OFF\npublic static final int STATE_UNDEFINED\npublic static final int STATE_ON\npublic static final int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate int mNum\nprivate int mNum2\nprivate int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient android.net.LinkAddress[] mLinkAddresses6\ntransient int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static java.lang.String defaultName4()\nprivate int[] lazyInitTmpStorage()\npublic android.net.LinkAddress[] getLinkAddresses4()\nprivate boolean patternEquals(java.util.regex.Pattern)\nprivate int patternHashCode()\nprivate void onConstructed()\npublic void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)") @Deprecated diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java index 0f8c663f5d4b..2efa193e7e2a 100644 --- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java +++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java @@ -85,7 +85,7 @@ public class SampleWithCustomBuilder implements Parcelable { - // Code below generated by codegen v1.0.4. + // Code below generated by codegen v1.0.5. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -151,6 +151,26 @@ public class SampleWithCustomBuilder implements Parcelable { @DataClass.Generated.Member public int describeContents() { return 0; } + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + protected SampleWithCustomBuilder(Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + long _delayAmount = in.readLong(); + TimeUnit _delayUnit = unparcelDelayUnit(in); + long _creationTimestamp = in.readLong(); + + this.delayAmount = _delayAmount; + this.delayUnit = _delayUnit; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, delayUnit); + this.creationTimestamp = _creationTimestamp; + + // onConstructed(); // You can define this method to get a callback + } + @DataClass.Generated.Member public static final @NonNull Parcelable.Creator<SampleWithCustomBuilder> CREATOR = new Parcelable.Creator<SampleWithCustomBuilder>() { @@ -160,18 +180,8 @@ public class SampleWithCustomBuilder implements Parcelable { } @Override - @SuppressWarnings({"unchecked", "RedundantCast"}) public SampleWithCustomBuilder createFromParcel(Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - long _delayAmount = in.readLong(); - TimeUnit _delayUnit = unparcelDelayUnit(in); - long _creationTimestamp = in.readLong(); - return new SampleWithCustomBuilder( - _delayAmount, - _delayUnit, - _creationTimestamp); + return new SampleWithCustomBuilder(in); } }; @@ -239,8 +249,8 @@ public class SampleWithCustomBuilder implements Parcelable { } @DataClass.Generated( - time = 1570139501160L, - codegenVersion = "1.0.4", + time = 1570231098303L, + codegenVersion = "1.0.5", sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java", inputSignatures = " long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n long creationTimestamp\nprivate static java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt index 5061be2091e5..92da9dab863b 100644 --- a/tools/codegen/src/com/android/codegen/ClassInfo.kt +++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt @@ -38,6 +38,11 @@ open class ClassInfo(val sourceLines: List<String>) { val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration) .implementedTypes.map { it.asString() } + val superClass = run { + val superClasses = (fileAst.types[0] as ClassOrInterfaceDeclaration).extendedTypes + if (superClasses.isNonEmpty) superClasses[0] else null + } + val ClassName = classAst.nameAsString private val genericArgsAst = classAst.typeParameters val genericArgs = if (genericArgsAst.isEmpty()) "" else { diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt index 1f0d4b8a7ec9..bd72d9e7ec21 100644 --- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt +++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt @@ -1,6 +1,7 @@ package com.android.codegen import com.github.javaparser.ast.Modifier +import com.github.javaparser.ast.body.CallableDeclaration import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration import com.github.javaparser.ast.body.TypeDeclaration import com.github.javaparser.ast.expr.* @@ -37,6 +38,7 @@ class ClassPrinter( val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") } val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") } val Parcelable by lazy { classRef("android.os.Parcelable") } + val Parcel by lazy { classRef("android.os.Parcel") } val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") } init { @@ -354,7 +356,9 @@ class ClassPrinter( } fun hasMethod(name: String, vararg argTypes: String): Boolean { - return classAst.methods.any { + val members: List<CallableDeclaration<*>> = + if (name == ClassName) classAst.constructors else classAst.methods + return members.any { it.name.asString() == name && it.parameters.map { it.type.asString() } == argTypes.toList() } @@ -365,6 +369,10 @@ class ClassPrinter( .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) } .filter { hasMethod("lazyInit${it.NameUpperCamel}") } + val extendsParcelableClass by lazy { + Parcelable !in superInterfaces && superClass != null + } + init { val builderFactoryOverride = classAst.methods.find { it.isStatic && it.nameAsString == "builder" diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt index 865340566019..5a95676c1dc8 100644 --- a/tools/codegen/src/com/android/codegen/Generators.kt +++ b/tools/codegen/src/com/android/codegen/Generators.kt @@ -422,6 +422,10 @@ fun ClassPrinter.generateParcelable() { +"// void parcelFieldName(Parcel dest, int flags) { ... }" +"" + if (extendsParcelableClass) { + +"super.writeToParcel(dest, flags);\n" + } + if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) { +"$flagStorageType flg = 0;" booleanFields.forEachApply { @@ -463,6 +467,123 @@ fun ClassPrinter.generateParcelable() { +"" } + if (!hasMethod(ClassName, Parcel)) { + val visibility = if (classAst.isFinal) "/* package-private */" else "protected" + + +"/** @hide */" + +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})" + +GENERATED_MEMBER_HEADER + "$visibility $ClassName($Parcel in) {" { + +"// You can override field unparcelling by defining methods like:" + +"// static FieldType unparcelFieldName(Parcel in) { ... }" + +"" + + if (extendsParcelableClass) { + +"super(in);\n" + } + + if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) { + +"$flagStorageType flg = in.read$FlagStorageType();" + } + booleanFields.forEachApply { + +"$Type $_name = (flg & $fieldBit) != 0;" + } + nonBooleanFields.forEachApply { + + // Handle customized parceling + val customParcellingMethod = "unparcel$NameUpperCamel" + if (hasMethod(customParcellingMethod, Parcel)) { + +"$Type $_name = $customParcellingMethod(in);" + } else if (customParcellingClass != null) { + +"$Type $_name = $sParcelling.unparcel(in);" + } else if (hasAnnotation("@$DataClassEnum")) { + val ordinal = "${_name}Ordinal" + +"int $ordinal = in.readInt();" + +"$Type $_name = $ordinal < 0 ? null : $FieldClass.values()[$ordinal];" + } else { + val methodArgs = mutableListOf<String>() + + // Create container if any + val containerInitExpr = when { + FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()" + FieldClass == "List" || FieldClass == "ArrayList" -> + "new ${classRef("java.util.ArrayList")}<>()" + else -> "" + } + val passContainer = containerInitExpr.isNotEmpty() + + // nullcheck + + // "FieldType fieldName = (FieldType)" + if (passContainer) { + methodArgs.add(_name) + !"$Type $_name = " + if (mayBeNull) { + +"null;" + !"if ((flg & $fieldBit) != 0) {" + pushIndent() + +"" + !"$_name = " + } + +"$containerInitExpr;" + } else { + !"$Type $_name = " + if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : " + if (ParcelMethodsSuffix == "StrongInterface") { + !"$FieldClass.Stub.asInterface(" + } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" && + (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") && + ParcelMethodsSuffix != "Parcelable") { + !"($FieldClass) " + } + } + + // Determine method args + when { + ParcelMethodsSuffix == "Parcelable" -> + methodArgs += "$FieldClass.class.getClassLoader()" + ParcelMethodsSuffix == "SparseArray" -> + methodArgs += "$FieldInnerClass.class.getClassLoader()" + ParcelMethodsSuffix == "TypedObject" -> + methodArgs += "$FieldClass.CREATOR" + ParcelMethodsSuffix == "TypedArray" -> + methodArgs += "$FieldInnerClass.CREATOR" + ParcelMethodsSuffix == "Map" -> + methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()" + ParcelMethodsSuffix.startsWith("Parcelable") + || (isList || isArray) + && FieldInnerType !in PRIMITIVE_TYPES + "String" -> + methodArgs += "$FieldInnerClass.class.getClassLoader()" + } + + // ...in.readFieldType(args...); + when { + ParcelMethodsSuffix == "StrongInterface" -> !"in.readStrongBinder" + isArray -> !"in.create$ParcelMethodsSuffix" + else -> !"in.read$ParcelMethodsSuffix" + } + !"(${methodArgs.joinToString(", ")})" + if (ParcelMethodsSuffix == "StrongInterface") !")" + +";" + + // Cleanup if passContainer + if (passContainer && mayBeNull) { + popIndent() + rmEmptyLine() + +"\n}" + } + } + } + + +"" + fields.forEachApply { + !"this." + generateSetFrom(_name) + } + + generateOnConstructedCallback() + } + } + if (classAst.fields.none { it.variables[0].nameAsString == "CREATOR" }) { val Creator = classRef("android.os.Parcelable.Creator") @@ -477,107 +598,8 @@ fun ClassPrinter.generateParcelable() { } +"@Override" - +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})" "public $ClassName createFromParcel($Parcel in)" { - +"// You can override field unparcelling by defining methods like:" - +"// static FieldType unparcelFieldName(Parcel in) { ... }" - +"" - if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) { - +"$flagStorageType flg = in.read$FlagStorageType();" - } - booleanFields.forEachApply { - +"$Type $_name = (flg & $fieldBit) != 0;" - } - nonBooleanFields.forEachApply { - - // Handle customized parceling - val customParcellingMethod = "unparcel$NameUpperCamel" - if (hasMethod(customParcellingMethod, Parcel)) { - +"$Type $_name = $customParcellingMethod(in);" - } else if (customParcellingClass != null) { - +"$Type $_name = $sParcelling.unparcel(in);" - } else if (hasAnnotation("@$DataClassEnum")) { - val ordinal = "${_name}Ordinal" - +"int $ordinal = in.readInt();" - +"$Type $_name = $ordinal < 0 ? null : $FieldClass.values()[$ordinal];" - } else { - val methodArgs = mutableListOf<String>() - - // Create container if any - val containerInitExpr = when { - FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()" - FieldClass == "List" || FieldClass == "ArrayList" -> - "new ${classRef("java.util.ArrayList")}<>()" - else -> "" - } - val passContainer = containerInitExpr.isNotEmpty() - - // nullcheck + - // "FieldType fieldName = (FieldType)" - if (passContainer) { - methodArgs.add(_name) - !"$Type $_name = " - if (mayBeNull) { - +"null;" - !"if ((flg & $fieldBit) != 0) {" - pushIndent() - +"" - !"$_name = " - } - +"$containerInitExpr;" - } else { - !"$Type $_name = " - if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : " - if (ParcelMethodsSuffix == "StrongInterface") { - !"$FieldClass.Stub.asInterface(" - } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" && - (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") && - ParcelMethodsSuffix != "Parcelable") { - !"($FieldClass) " - } - } - - // Determine method args - when { - ParcelMethodsSuffix == "Parcelable" -> - methodArgs += "$FieldClass.class.getClassLoader()" - ParcelMethodsSuffix == "SparseArray" -> - methodArgs += "$FieldInnerClass.class.getClassLoader()" - ParcelMethodsSuffix == "TypedObject" -> - methodArgs += "$FieldClass.CREATOR" - ParcelMethodsSuffix == "TypedArray" -> - methodArgs += "$FieldInnerClass.CREATOR" - ParcelMethodsSuffix == "Map" -> - methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()" - ParcelMethodsSuffix.startsWith("Parcelable") - || (isList || isArray) - && FieldInnerType !in PRIMITIVE_TYPES + "String" -> - methodArgs += "$FieldInnerClass.class.getClassLoader()" - } - - // ...in.readFieldType(args...); - when { - ParcelMethodsSuffix == "StrongInterface" -> !"in.readStrongBinder" - isArray -> !"in.create$ParcelMethodsSuffix" - else -> !"in.read$ParcelMethodsSuffix" - } - !"(${methodArgs.joinToString(", ")})" - if (ParcelMethodsSuffix == "StrongInterface") !")" - +";" - - // Cleanup if passContainer - if (passContainer && mayBeNull) { - popIndent() - rmEmptyLine() - +"\n}" - } - } - } - "return new $ClassType(" { - fields.forEachTrimmingTrailingComma { - +"$_name," - } - } + ";" + +"return new $ClassName(in);" } rmEmptyLine() } + ";" diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt index 580467433756..c91eca94a9c0 100755 --- a/tools/codegen/src/com/android/codegen/Main.kt +++ b/tools/codegen/src/com/android/codegen/Main.kt @@ -146,8 +146,7 @@ fun main(args: Array<String>) { generateConstructor("public") } else if (FeatureFlag.BUILDER() || FeatureFlag.COPY_CONSTRUCTOR() - || FeatureFlag.WITHERS() - || FeatureFlag.PARCELABLE()) { + || FeatureFlag.WITHERS()) { generateConstructor("/* package-private */") } if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor() diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt index 1cc7ef338cc3..a36f2c838787 100644 --- a/tools/codegen/src/com/android/codegen/SharedConstants.kt +++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt @@ -1,7 +1,7 @@ package com.android.codegen const val CODEGEN_NAME = "codegen" -const val CODEGEN_VERSION = "1.0.4" +const val CODEGEN_VERSION = "1.0.5" const val CANONICAL_BUILDER_CLASS = "Builder" const val BASE_BUILDER_CLASS = "BaseBuilder" |