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
This commit is contained in:
Eugene Susla
2019-10-03 17:22:44 -07:00
parent 2f49522757
commit 8cb1a41714
13 changed files with 600 additions and 194 deletions

View File

@@ -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 && \

View File

@@ -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;

View File

@@ -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() {}
}

View File

@@ -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;

View File

@@ -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() {}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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()
} + ";"

View File

@@ -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()

View File

@@ -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"