├── .gitignore
├── .travis.yml
├── LICENSE
├── ParcelablePlease-intellij-plugin
├── META-INF
│ └── plugin.xml
├── ParcelablePlease-intellij-plugin.jar
├── images
│ ├── generate.png
│ └── intellij-plugin.png
├── resources
│ └── META-INF
│ │ └── plugin.xml
└── src
│ └── com
│ └── hannesdorfmann
│ └── parcelableplease
│ └── plugin
│ ├── CodeGenerator.java
│ └── ParcelablePleaseAction.java
├── README.md
├── annotation
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── hannesdorfmann
│ └── parcelableplease
│ ├── ParcelBagger.java
│ └── annotation
│ ├── Bagger.java
│ ├── ParcelableNoThanks.java
│ ├── ParcelablePlease.java
│ └── ParcelableThisPlease.java
├── checkstyle.xml
├── pom.xml
├── processor
├── .gitignore
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ ├── com
│ │ │ └── hannesdorfmann
│ │ │ │ └── parcelableplease
│ │ │ │ └── processor
│ │ │ │ ├── ParcelableField.java
│ │ │ │ ├── ParcelablePleaseProcessor.java
│ │ │ │ ├── ProcessorMessage.java
│ │ │ │ ├── codegenerator
│ │ │ │ ├── AbsCodeGen.java
│ │ │ │ ├── BaggerCodeGen.java
│ │ │ │ ├── CodeGenerator.java
│ │ │ │ ├── FieldCodeGen.java
│ │ │ │ ├── SupportedTypes.java
│ │ │ │ ├── android
│ │ │ │ │ ├── BundleCodeGen.java
│ │ │ │ │ ├── ParcelableCodeGen.java
│ │ │ │ │ ├── SparseArrayCodeGen.java
│ │ │ │ │ └── SparseBooleanCodeGen.java
│ │ │ │ ├── collection
│ │ │ │ │ ├── AbsListCodeGen.java
│ │ │ │ │ ├── ParcelableArrayCodeGen.java
│ │ │ │ │ ├── PrimitiveArrayCodeGen.java
│ │ │ │ │ └── StringListCodeGen.java
│ │ │ │ ├── other
│ │ │ │ │ ├── DateCodeGen.java
│ │ │ │ │ └── SerializeableCodeGen.java
│ │ │ │ ├── primitives
│ │ │ │ │ └── BooleanCodeGen.java
│ │ │ │ └── primitiveswrapper
│ │ │ │ │ ├── AbsPrimitiveWrapperCodeGen.java
│ │ │ │ │ └── BooleanWrapperCodeGen.java
│ │ │ │ └── util
│ │ │ │ ├── CodeGenInfo.java
│ │ │ │ └── TypeUtils.java
│ │ └── repacked
│ │ │ └── com
│ │ │ └── squareup
│ │ │ └── javawriter
│ │ │ └── JavaWriter.java
│ └── resources
│ │ └── META-INF
│ │ └── services
│ │ └── javax.annotation.processing.Processor
│ └── test
│ └── java
│ └── com
│ └── hannesdorfmann
│ └── parcelableplease
│ └── processor
│ └── ParcelablePleaseProcessorTest.java
└── sample
├── .gitignore
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── hannesdorfmann
│ │ └── parcelableplease
│ │ └── sample
│ │ ├── MainActivity.java
│ │ └── model
│ │ ├── Banana.java
│ │ ├── Fruit.java
│ │ ├── FruitType.java
│ │ ├── FruitTypeBagger.java
│ │ └── Orange.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── menu_main.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .factorypath
3 | .project
4 | .settings
5 | eclipsebin
6 |
7 | bin
8 | gen
9 | build
10 | out
11 | lib
12 |
13 | target
14 | pom.xml.*
15 | release.properties
16 | log
17 | settings.xml
18 |
19 | .idea
20 | *.iml
21 | *.iws
22 | classes
23 |
24 | obj
25 |
26 | .DS_Store
27 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 | jdk:
4 | - oraclejdk7
5 | - oraclejdk8
6 |
7 | #env:
8 | # global:
9 | # - secure: "TM2N/yo3azbA7+J6WG0W1RmK4vvS7b4JzvJP8NcXpoZCQw2Je1nQqmKS3F/04/DEUf8+SKVh2thKEeUxLN8knCO0OQLxeKIFj9PLvtgHnV8beB+pPxUdpEvMlB6ISeDsOZ098zoax28zfMwR7+uMeGe2VbtTSpwtqt4jkWx3ooA="
10 | # - secure: "A5flBI/PCmmxuHjqG73CIXqHYg8X1GWloA3jv0zrhCAuK5m3nAvt7JY2qom22ttEY9JI32dlArxhusrKib18gKNgZbxzoN5PydkG6T0uuGZw+uZM6jPiTlvkC0F4ikL6lg1dBap4BoakDMwAPfb11UpETamBGKOWdopLqw6T6w0="
11 |
12 | branches:
13 | except:
14 | - gh-pages
15 |
16 | notifications:
17 | email: false
18 |
19 | sudo: false
20 |
21 | cache:
22 | directories:
23 | - $HOME/.m2
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2014 Hannes Dorfmann
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/ParcelablePlease-intellij-plugin/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | com.hannesdorfmann.parcelableplease.plugin
3 | ParcelablePlease
4 | 1.0.2
5 | Hannes Dorfmann
6 |
7 | ParcelablePlease on github
10 | ]]>
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
24 |
25 | com.intellij.modules.java
26 | com.intellij.modules.androidstudio
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ParcelablePlease-intellij-plugin/ParcelablePlease-intellij-plugin.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/ParcelablePlease-intellij-plugin/ParcelablePlease-intellij-plugin.jar
--------------------------------------------------------------------------------
/ParcelablePlease-intellij-plugin/images/generate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/ParcelablePlease-intellij-plugin/images/generate.png
--------------------------------------------------------------------------------
/ParcelablePlease-intellij-plugin/images/intellij-plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/ParcelablePlease-intellij-plugin/images/intellij-plugin.png
--------------------------------------------------------------------------------
/ParcelablePlease-intellij-plugin/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | com.hannesdorfmann.parcelableplease.plugin
3 | ParcelablePlease
4 | 1.0.2
5 | Hannes Dorfmann
6 |
7 | ParcelablePlease on github
10 | ]]>
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
24 |
25 | com.intellij.modules.java
26 | com.intellij.modules.androidstudio
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ParcelablePlease-intellij-plugin/src/com/hannesdorfmann/parcelableplease/plugin/CodeGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 Hannes Dormfann (www.hannesdorfmann.com)
3 | *
4 | *
5 | * Parts of this code are taken from Michał Charmas.
6 | *
7 | * Copyright (C) 2013 Michał Charmas (http://blog.charmas.pl)
8 | *
9 | * Licensed under the Apache License, Version 2.0 (the "License");
10 | * you may not use this file except in compliance with the License.
11 | * You may obtain a copy of the License at
12 | *
13 | * http://www.apache.org/licenses/LICENSE-2.0
14 | *
15 | * Unless required by applicable law or agreed to in writing, software
16 | * distributed under the License is distributed on an "AS IS" BASIS,
17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 | * See the License for the specific language governing permissions and
19 | * limitations under the License.
20 | */
21 |
22 |
23 | package com.hannesdorfmann.parcelableplease.plugin;
24 |
25 | import com.intellij.codeInsight.AnnotationUtil;
26 | import com.intellij.psi.JavaPsiFacade;
27 | import com.intellij.psi.PsiClass;
28 | import com.intellij.psi.PsiClassType;
29 | import com.intellij.psi.PsiElementFactory;
30 | import com.intellij.psi.PsiField;
31 | import com.intellij.psi.PsiFile;
32 | import com.intellij.psi.PsiImportList;
33 | import com.intellij.psi.PsiImportStatementBase;
34 | import com.intellij.psi.PsiJavaCodeReferenceElement;
35 | import com.intellij.psi.PsiJavaFile;
36 | import com.intellij.psi.PsiMethod;
37 | import com.intellij.psi.PsiParameter;
38 | import com.intellij.psi.PsiParameterList;
39 | import com.intellij.psi.PsiReferenceList;
40 | import com.intellij.psi.codeStyle.JavaCodeStyleManager;
41 |
42 | /**
43 | * Generates the real code for ParcelablePlease that will be injected in intellij code editor
44 | * window
45 | *
46 | * @author Hannes Dorfmann
47 | */
48 | public class CodeGenerator {
49 |
50 | private static final String PARCELABLE_PLEASE_SUFFIX = "ParcelablePlease";
51 |
52 | private static final String ANNOTATION_PACKAGE =
53 | "com.hannesdorfmann.parcelableplease.annotation";
54 |
55 | private static final String ANNOTATION_NAME = "ParcelablePlease";
56 |
57 | private PsiClass psiClass;
58 |
59 | public CodeGenerator(PsiClass psiClass) {
60 | this.psiClass = psiClass;
61 | }
62 |
63 | private String generateCreator() {
64 |
65 | String className = psiClass.getName();
66 | String parcelablePleaseClass = getParcelablePleaseClassName();
67 |
68 | StringBuilder sb = new StringBuilder("public static final android.os.Parcelable.Creator<");
69 | sb.append(className)
70 | .append("> CREATOR = new android.os.Parcelable.Creator<")
71 | .append(className)
72 | .append(">(){")
73 | .append("public ")
74 | .append(className)
75 | .append(" createFromParcel(android.os.Parcel source) {")
76 | .append(className)
77 | .append(" target = new ")
78 | .append(className)
79 | .append("();")
80 | .append(parcelablePleaseClass)
81 | .append(".readFromParcel(target, source); return target;}")
82 | .append("public ")
83 | .append(className)
84 | .append("[] newArray(int size) {")
85 | .append("return new ")
86 | .append(className)
87 | .append("[size];}")
88 | .append("};");
89 |
90 | return sb.toString();
91 | }
92 |
93 | private String generateWriteToParcel() {
94 |
95 | String parcelablePleaseClass = getParcelablePleaseClassName();
96 |
97 | StringBuilder sb = new StringBuilder(
98 | "@Override public void writeToParcel(android.os.Parcel dest, int flags) {");
99 |
100 | sb.append(parcelablePleaseClass).append(".writeToParcel(this, dest, flags);").append("}");
101 |
102 | return sb.toString();
103 | }
104 |
105 | private String generateDescribeContents() {
106 | return "@Override public int describeContents() { return 0; }";
107 | }
108 |
109 | private void addImport(PsiElementFactory elementFactory, String fullyQualifiedName){
110 | final PsiFile file = psiClass.getContainingFile();
111 | if (!(file instanceof PsiJavaFile)) {
112 | return;
113 | }
114 | final PsiJavaFile javaFile = (PsiJavaFile)file;
115 |
116 | final PsiImportList importList = javaFile.getImportList();
117 | if (importList == null) {
118 | return;
119 | }
120 |
121 | // Check if already imported
122 | for (PsiImportStatementBase is : importList.getAllImportStatements()) {
123 | String impQualifiedName = is.getImportReference().getQualifiedName();
124 | if (fullyQualifiedName.equals(impQualifiedName)){
125 | return; // Already imported so nothing neede
126 | }
127 |
128 | }
129 |
130 | // Not imported yet so add it
131 | importList.add(elementFactory.createImportStatementOnDemand(fullyQualifiedName));
132 | }
133 |
134 |
135 | public void clearPrevious(){
136 |
137 | // Delete creator
138 | PsiField creatorField = psiClass.findFieldByName("CREATOR", false);
139 | if (creatorField != null) {
140 | creatorField.delete();
141 | }
142 |
143 | // Delete Methods
144 | findAndRemoveMethod("describeContents");
145 | findAndRemoveMethod("writeToParcel", "android.os.Parcel", "int");
146 |
147 | }
148 |
149 | /**
150 | * Finds and removes a given method
151 | * @param methodName
152 | * @param arguments
153 | */
154 | private void findAndRemoveMethod(String methodName, String... arguments) {
155 | // Maybe there's an easier way to do this with mClass.findMethodBySignature(), but I'm not an expert on Psi*
156 | PsiMethod[] methods = psiClass.findMethodsByName(methodName, false);
157 |
158 | for (PsiMethod method : methods) {
159 | PsiParameterList parameterList = method.getParameterList();
160 |
161 | if (parameterList.getParametersCount() == arguments.length) {
162 | boolean shouldDelete = true;
163 |
164 | PsiParameter[] parameters = parameterList.getParameters();
165 |
166 | for (int i = 0; i < arguments.length; i++) {
167 | if (!parameters[i].getType().getCanonicalText().equals(arguments[i])) {
168 | shouldDelete = false;
169 | }
170 | }
171 |
172 | if (shouldDelete) {
173 | method.delete();
174 | }
175 | }
176 | }
177 | }
178 |
179 | /**
180 | * Generate and insert the Parcel and ParcelablePlease code
181 | */
182 | public void generate() {
183 |
184 | PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(psiClass.getProject());
185 | JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(psiClass.getProject());
186 |
187 | // Clear any previous
188 | clearPrevious();
189 |
190 | // Implements parcelable
191 | makeClassImplementParcelable(elementFactory, styleManager);
192 |
193 | // @ParcelablePlease Annotation
194 | addAnnotation(elementFactory, styleManager);
195 |
196 | // Creator
197 | PsiField creatorField = elementFactory.createFieldFromText(generateCreator(), psiClass);
198 |
199 | // Describe contents method
200 | PsiMethod describeContentsMethod =
201 | elementFactory.createMethodFromText(generateDescribeContents(), psiClass);
202 |
203 | // Method for writing to the parcel
204 | PsiMethod writeToParcelMethod =
205 | elementFactory.createMethodFromText(generateWriteToParcel(), psiClass);
206 |
207 | styleManager.shortenClassReferences(
208 | psiClass.addBefore(describeContentsMethod, psiClass.getLastChild()));
209 |
210 | styleManager.shortenClassReferences(
211 | psiClass.addBefore(writeToParcelMethod, psiClass.getLastChild()));
212 |
213 | styleManager.shortenClassReferences(psiClass.addBefore(creatorField, psiClass.getLastChild()));
214 | }
215 |
216 | /**
217 | * Add the @Parcelable annotation if not already annotated
218 | */
219 | private void addAnnotation(PsiElementFactory elementFactory, JavaCodeStyleManager styleManager) {
220 |
221 | boolean annotated = AnnotationUtil.isAnnotated(psiClass, ANNOTATION_PACKAGE+"."+ANNOTATION_NAME, false);
222 |
223 | if (!annotated) {
224 | styleManager.shortenClassReferences(psiClass.getModifierList().addAnnotation(
225 | ANNOTATION_NAME));
226 | }
227 | }
228 |
229 | /**
230 | * Make the class implementing Parcelable
231 | */
232 | private void makeClassImplementParcelable(PsiElementFactory elementFactory, JavaCodeStyleManager styleManager) {
233 | final PsiClassType[] implementsListTypes = psiClass.getImplementsListTypes();
234 | final String implementsType = "android.os.Parcelable";
235 |
236 | for (PsiClassType implementsListType : implementsListTypes) {
237 | PsiClass resolved = implementsListType.resolve();
238 |
239 | // Already implements Parcelable, no need to add it
240 | if (resolved != null && implementsType.equals(resolved.getQualifiedName())) {
241 | return;
242 | }
243 | }
244 |
245 | PsiJavaCodeReferenceElement implementsReference =
246 | elementFactory.createReferenceFromText(implementsType, psiClass);
247 | PsiReferenceList implementsList = psiClass.getImplementsList();
248 |
249 | if (implementsList != null) {
250 | styleManager.shortenClassReferences(implementsList.add(implementsReference));
251 | }
252 | }
253 |
254 | private String getParcelablePleaseClassName() {
255 | String className = psiClass.getName();
256 | StringBuilder classNameBuilder = new StringBuilder();
257 | classNameBuilder.append(className);
258 | classNameBuilder.append(PARCELABLE_PLEASE_SUFFIX);
259 | PsiClass containingClass = psiClass.getContainingClass();
260 | while (containingClass != null) {
261 | classNameBuilder.insert(0, '$');
262 | classNameBuilder.insert(0, containingClass.getName());
263 | containingClass = containingClass.getContainingClass();
264 | }
265 |
266 | return classNameBuilder.toString();
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/ParcelablePlease-intellij-plugin/src/com/hannesdorfmann/parcelableplease/plugin/ParcelablePleaseAction.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.plugin;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.LangDataKeys;
6 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
7 | import com.intellij.openapi.command.WriteCommandAction;
8 | import com.intellij.openapi.editor.Editor;
9 | import com.intellij.psi.PsiClass;
10 | import com.intellij.psi.PsiElement;
11 | import com.intellij.psi.PsiFile;
12 | import com.intellij.psi.util.PsiTreeUtil;
13 | /**
14 | * A simple plugin for generating the boilerplateCode of ParcelablePlease
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | public class ParcelablePleaseAction extends AnAction {
19 | public void actionPerformed(AnActionEvent e) {
20 |
21 | final PsiClass psiClass = getPsiClassFromContext(e);
22 |
23 | // Generate Code
24 | new WriteCommandAction.Simple(psiClass.getProject(), psiClass.getContainingFile()) {
25 | @Override
26 | protected void run() throws Throwable {
27 | new CodeGenerator(psiClass).generate();
28 | }
29 | }.execute();
30 | }
31 |
32 | @Override
33 | public void update(AnActionEvent e) {
34 | PsiClass psiClass = getPsiClassFromContext(e);
35 | e.getPresentation().setEnabled(psiClass != null && !psiClass.isEnum() && !psiClass.isInterface());
36 | }
37 |
38 |
39 | /**
40 | * Get the class where currently the curser is
41 | */
42 | private PsiClass getPsiClassFromContext(AnActionEvent e) {
43 | PsiFile psiFile = e.getData(LangDataKeys.PSI_FILE);
44 | Editor editor = e.getData(PlatformDataKeys.EDITOR);
45 |
46 |
47 | if (psiFile == null || editor == null) {
48 | return null;
49 | }
50 |
51 | int offset = editor.getCaretModel().getOffset();
52 | PsiElement element = psiFile.findElementAt(offset);
53 |
54 | return PsiTreeUtil.getParentOfType(element, PsiClass.class);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ParcelablePlease
2 | An AnnotationProcessor for generating Android Parcelable boilerplate code. [See this blog entry](http://hannesdorfmann.com/android/ParcelablePlease) for comparison with other parcel libraries.
3 |
4 | # Dependency
5 | Latest version: [](https://maven-badges.herokuapp.com/maven-central/com.hannesdorfmann.parcelableplease/annotation)
6 |
7 | ```groovy
8 | compile 'com.hannesdorfmann.parcelableplease:annotation:x.x.x'
9 | apt 'com.hannesdorfmann.parcelableplease:processor:x.x.x'
10 | ```
11 | In android studio you need to apply Hugo Visser's awesome [android-apt](https://bitbucket.org/hvisser/android-apt) gradle plugin to enable annotation processing.
12 |
13 | # How to use
14 | Simply annotate the classes you want to make Parcelable with `@ParcelablePlease` and implement the `Parcelable` as well as the `CREATOR` (This step can be automated by using the Android Studio plugin, see below).
15 |
16 | ```java
17 | @ParcelablePlease
18 | public class Model implements Parcelable {
19 |
20 | int id;
21 | String name;
22 | OtherModel otherModel;
23 |
24 | @Override public int describeContents() {
25 | return 0;
26 | }
27 |
28 | @Override public void writeToParcel(Parcel dest, int flags) {
29 | ModelParcelablePlease.writeToParcel(this, dest, flags);
30 | }
31 |
32 | public static final Creator CREATOR = new Creator() {
33 | public Model createFromParcel(Parcel source) {
34 | Model target = new Model();
35 | ModelParcelablePlease.readFromParcel(target, source);
36 | return target;
37 | }
38 |
39 | public Model[] newArray(int size) {
40 | return new Model[size];
41 | }
42 | };
43 | }
44 |
45 | ```
46 | The `ParcelablePlease` annotation processor will generate a class named `ClassName + ParcelablePlease` for you with all the code for writing and reading data in the Parcel. So from the example above: `ModelParcelablePlease` is generated and provides two static methods: `ModelParcelablePlease.readFromParcel(Model, Parcel)` and `ModelParcelablePlease.writeToParcel(Model, Parcel, int)`
47 |
48 | Once you have done this basic setup by connecting the generated code with your Model class you can change the model class, add fields, remove fields etc. without worring about `Parcelable` because `ParcelablePlease` will generate the code for you everytime you compile.
49 |
50 | # Android Studio Plugin
51 | Like mentioned above you have to write few lines of code to connect the Parcelable class with the generated code. Don't worry, you don't have to do this by hand. There is a Android Studio / IntelliJ plugin that can do that for you:
52 |
53 | 1. Open Android Studio / IntelliJ
54 | 2. Open the Preferences (on Mac with `⌘ + ;` )
55 | 3. Type in the searchbox "plugin" to navigate quickly to the plugins section
56 | 4. Click on _Browse repositories..._ button
57 | 5. Search for _ParcelablePlease_ and install this plugin
58 | 6. Restart Android Studio
59 | 7. Create a Model class and open the Generate Menu (on Mac with ``⌘ + n` ). Note that the cursor must be somewhere in the code of the class.
60 |
61 | 
62 |
63 |
64 | Remember that you may have to compile your project to make Android Studio run annotation Processing which will generate the ParcelPlease classes.
65 |
66 |
67 | # Supported types
68 |
69 | - **Primitives**
70 | - byte
71 | - boolean
72 | - double
73 | - float
74 | - int
75 | - long
76 | - String
77 |
78 | - **Primitive wrappers**
79 | - Byte
80 | - Boolean
81 | - Double
82 | - Float
83 | - Int
84 | - Long
85 |
86 | - **Android specific**
87 | - Parcelable (anything that implements Parcelable)
88 | - Bundle
89 | - SparseBooleanArray
90 |
91 | - **Arrays**
92 | - int[]
93 | - long[]
94 | - double[]
95 | - String[]
96 | - float[]
97 | - char[]
98 | - boolean[]
99 | - byte[]
100 | - Parcelable[] - array of anything that implements Parcelable
101 |
102 | - **Other**
103 | - Serializable
104 | - java.util.Date (by simpling passing time as millis)
105 |
106 |
107 | - **Collections**
108 | - List extends Parcelalble>
109 | - ArrayList extends Parcelable>
110 | - LinkedList extends Parcelable>
111 | - CopyOnWriteArrayList extends Parcelable>
112 | - List
113 |
114 |
115 | # Bagger
116 | Do you want to make a field Parcelable but it's not listed in the supported types list from above (i.e. `java.util.Map`)? No Problem: You can provide your own implementation implementing a `ParcelBagger` like this:
117 | ```java
118 | public class DateBagger implements ParcelBagger {
119 |
120 | @Override public void write(Date value, Parcel out, int flags) {
121 | if (value == null) {
122 | out.writeLong(-1);
123 | } else {
124 | out.writeLong(value.getTime());
125 | }
126 | }
127 |
128 | @Override public Date read(Parcel in) {
129 |
130 | long timeMillis = in.readLong();
131 | if (timeMillis == -1) {
132 | return null;
133 | }
134 |
135 | return new Date(timeMillis);
136 | }
137 | }
138 | ```
139 |
140 | You can use your ParcelBagger with the `@Bagger` annotation like this:
141 |
142 | ```java
143 | @ParcelablePlease
144 | public class Person implements Parcelable {
145 |
146 | int id;
147 | String name;
148 |
149 | @Bagger(DateBagger.class)
150 | Date date;
151 |
152 | }
153 | ```
154 |
155 | Remember that you have to take care about special cases like what if the value is null.
156 | **Note** that `java.util.Date` is already supported by `ParcelablePlease`. The example above is just to give you an idea of how a implementation could look like.
157 |
158 |
159 | # Configuration
160 | You can configure which fields should be serialized. There are two ways:
161 | 1. As default all class (and super classes) fields will be serialized. You can mark field's you don't want to serialize by annotating them with `@ParcelableNoThanks`
162 | 2. You can do the other way: You could change the settings to only serialize fields that are marked with `@ParcelableThisPlease ` like this:
163 | ```java
164 | @ParcelablePlease( allFields = false)
165 | public class Animal implements Parcelable {
166 |
167 | @ParcelableThisPlease
168 | String name;
169 |
170 | int age; // This will not be serialized
171 |
172 | }
173 | ```
174 |
175 |
176 | As default `ParcelablePlease` will throw a compile error if it tries to serialize private fields (private fields are not supported because of visibility issues). If your class marked with `@ParcelablePlease` contains private fields you could mark them as not parcelable with `@ParcelableNoThanks` or you could cofigure ParcelablePlease to skip private fields by using `@ParcelablePlease( ignorePrivateFields = true)`:
177 |
178 | ```java
179 | @ParcelablePlease( ignorePrivateFields = true)
180 | public class Person implements Parcelable {
181 |
182 | String name;
183 |
184 | private int age; // No compile error
185 |
186 | }
187 | ```
188 |
189 | # Limitations
190 | - **Fields** must have at least default (package) visibility. That means private fields are not supported.
191 | - **Private classes** are not supported because of visibilitiy issues
192 |
--------------------------------------------------------------------------------
/annotation/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .factorypath
3 | .project
4 | .settings
5 | eclipsebin
6 |
7 | bin
8 | gen
9 | build
10 | out
11 | lib
12 |
13 | target
14 | pom.xml.*
15 | release.properties
16 | log
17 | settings.xml
18 |
19 | .idea
20 | *.iml
21 | *.iws
22 | classes
23 |
24 | obj
25 |
26 | .DS_Store
27 |
--------------------------------------------------------------------------------
/annotation/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | parent
7 | com.hannesdorfmann.parcelableplease
8 | 1.0.3-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | annotation
13 |
14 | ParcelablePlease Annotations
15 |
16 |
17 |
18 | com.google.android
19 | android
20 | provided
21 |
22 |
23 |
24 | junit
25 | junit
26 | test
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | org.apache.maven.plugins
35 | maven-javadoc-plugin
36 |
37 |
38 | attach-javadocs
39 |
40 | jar
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.apache.maven.plugins
48 | maven-source-plugin
49 |
50 |
51 | attach-sources
52 |
53 | jar
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/hannesdorfmann/parcelableplease/ParcelBagger.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease;
2 |
3 | import android.os.Parcel;
4 |
5 | /**
6 | * A way to put a not Parcelable object into a Parcel and vice versa.
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | public interface ParcelBagger {
11 |
12 | /**
13 | * Write the value into the parcelable
14 | */
15 | public void write(T value, Parcel out, int flags);
16 |
17 | /**
18 | * Read the value from parcelable
19 | */
20 | public T read(Parcel in);
21 | }
22 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/hannesdorfmann/parcelableplease/annotation/Bagger.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.annotation;
2 |
3 | import com.hannesdorfmann.parcelableplease.ParcelBagger;
4 |
5 | /**
6 | * Annotate Fields you want to put in a Parcel which is not Parcelable.
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | public @interface Bagger {
11 | Class extends ParcelBagger>> value();
12 | }
13 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/hannesdorfmann/parcelableplease/annotation/ParcelableNoThanks.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Annotate fields not to be parcelable (transient)
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | @Target(ElementType.FIELD) @Retention(RetentionPolicy.CLASS) @Documented
15 | public @interface ParcelableNoThanks {
16 | }
17 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/hannesdorfmann/parcelableplease/annotation/ParcelablePlease.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Annotate classes that have
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | @Target(ElementType.TYPE) @Retention(RetentionPolicy.CLASS) @Documented
15 | public @interface ParcelablePlease {
16 |
17 | /**
18 | * Should all fields be parcelable.
19 | * Default is true.
20 | */
21 | boolean allFields() default true;
22 |
23 | /**
24 | * Should private fields be ignored?
25 | * Otherwise an error while compiling will be thrown if the class annotated with this Annotation
26 | * contains private fields.
27 | */
28 | boolean ignorePrivateFields() default false;
29 | }
30 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/hannesdorfmann/parcelableplease/annotation/ParcelableThisPlease.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Annotate fields with that if you don't want to use all
11 | * @author Hannes Dorfmann
12 | */
13 | @Target(ElementType.FIELD) @Retention(RetentionPolicy.CLASS) @Documented
14 | public @interface ParcelableThisPlease {
15 | }
16 |
--------------------------------------------------------------------------------
/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | org.sonatype.oss
9 | oss-parent
10 | 7
11 |
12 |
13 | com.hannesdorfmann.parcelableplease
14 | parent
15 | pom
16 | 1.0.3-SNAPSHOT
17 |
18 | ParcelablePlease Parent
19 | Generates Android Parcelable code
20 | https://github.com/sockeqwe/ParcelablePlease
21 |
22 |
23 | GitHub Issues
24 | http://github.com/sockeqwe/ParcelablePlease/issues
25 |
26 |
27 |
28 |
29 | Apache 2.0
30 | http://www.apache.org/licenses/LICENSE-2.0.txt
31 |
32 |
33 |
34 |
35 | Hannes Dorfmann
36 | http://www.hannesdorfmann.com
37 |
38 |
39 |
40 |
41 | annotation
42 | processor
43 |
44 |
45 |
46 |
47 | UTF-8
48 |
49 |
50 | 1.6
51 | 4.1.1.4
52 |
53 |
54 | 4.12
55 | 1.0-SNAPSHOT
56 | 1.0-SNAPSHOT
57 |
58 |
59 |
60 |
61 |
62 | ossrh
63 | https://oss.sonatype.org/content/repositories/snapshots
64 |
65 |
66 | ossrh
67 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | com.google.android
76 | android
77 | ${android.version}
78 |
79 |
80 |
81 | junit
82 | junit
83 | ${junit.version}
84 |
85 |
86 | com.google.testing.compile
87 | compile-testing
88 | ${compile-testing.version}
89 |
90 |
91 | com.google.truth
92 | truth
93 | ${truth.version}
94 | test
95 |
96 |
97 |
98 |
99 |
100 |
101 | autoincrement-versions-maven-plugin
102 | autoincrement-versions-maven-plugin
103 | http://autoincrement-versions-maven-plugin.googlecode.com/svn/repo
104 |
105 | true
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | org.apache.maven.plugins
115 | maven-invoker-plugin
116 | 1.7
117 |
118 |
119 |
120 | org.apache.maven.plugins
121 | maven-compiler-plugin
122 | 3.1
123 |
124 |
125 |
126 |
127 |
128 |
129 | org.apache.maven.plugins
130 | maven-compiler-plugin
131 |
132 | ${java.version}
133 | ${java.version}
134 | -Xlint:all
135 | true
136 | true
137 |
138 |
139 |
140 |
141 |
142 | org.apache.maven.plugins
143 | maven-javadoc-plugin
144 |
145 |
146 | attach-javadocs
147 |
148 | jar
149 |
150 |
151 |
152 |
153 |
154 |
155 | org.apache.maven.plugins
156 | maven-source-plugin
157 |
158 |
159 | attach-sources
160 |
161 | jar
162 |
163 |
164 |
165 |
166 |
167 |
168 | org.apache.maven.plugins
169 | maven-release-plugin
170 | 2.4.2
171 |
172 |
173 | org.apache.maven.scm
174 | maven-scm-provider-gitexe
175 | 1.9
176 |
177 |
178 |
179 | true
180 |
181 |
182 |
183 |
184 | org.apache.maven.plugins
185 | maven-checkstyle-plugin
186 | 2.10
187 |
188 | false
189 | true
190 | checkstyle.xml
191 |
192 |
193 |
194 | compile
195 |
196 | checkstyle
197 |
198 |
199 |
200 |
201 |
202 |
230 |
231 |
251 |
252 |
253 |
254 |
255 |
256 |
--------------------------------------------------------------------------------
/processor/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .factorypath
3 | .project
4 | .settings
5 | eclipsebin
6 |
7 | bin
8 | gen
9 | build
10 | out
11 | lib
12 |
13 | target
14 | pom.xml.*
15 | release.properties
16 | log
17 | settings.xml
18 |
19 | .idea
20 | *.iml
21 | *.iws
22 | classes
23 |
24 | obj
25 |
26 | .DS_Store
27 |
--------------------------------------------------------------------------------
/processor/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | parent
7 | com.hannesdorfmann.parcelableplease
8 | 1.0.3-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | processor
13 | ParcelablePlease Processor
14 |
15 |
16 |
17 | ${project.groupId}
18 | annotation
19 | ${project.version}
20 |
21 |
22 |
23 |
24 | junit
25 | junit
26 | test
27 |
28 |
29 |
30 | com.google.testing.compile
31 | compile-testing
32 | test
33 |
34 |
35 |
36 |
37 | com.google.truth
38 | truth
39 | test
40 |
41 |
42 | com.google.android
43 | android
44 | test
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | org.apache.maven.plugins
54 | maven-compiler-plugin
55 |
56 |
57 | default-compile
58 |
59 | compile
60 |
61 |
62 | -proc:none
63 |
64 |
65 |
66 | default-test-compile
67 |
68 | testCompile
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-invoker-plugin
78 |
79 | true
80 | ${project.build.directory}/it
81 |
82 | */pom.xml
83 |
84 | ${project.build.directory}/local-repo
85 | verify
86 |
87 | ${project.version}
88 | ${project.groupId}
89 |
90 |
91 |
92 |
93 | integration-test
94 |
95 | install
96 | run
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | org.apache.maven.plugins
105 | maven-javadoc-plugin
106 |
107 |
108 | attach-javadocs
109 |
110 | jar
111 |
112 |
113 |
114 |
115 |
116 |
117 | org.apache.maven.plugins
118 | maven-source-plugin
119 |
120 |
121 | attach-sources
122 |
123 | jar
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/ParcelableField.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor;
2 |
3 | import com.hannesdorfmann.parcelableplease.ParcelBagger;
4 | import com.hannesdorfmann.parcelableplease.annotation.Bagger;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.BaggerCodeGen;
6 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
7 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.SupportedTypes;
8 | import com.hannesdorfmann.parcelableplease.processor.util.CodeGenInfo;
9 | import java.lang.reflect.Constructor;
10 | import java.lang.reflect.Modifier;
11 | import java.util.List;
12 | import javax.lang.model.element.Element;
13 | import javax.lang.model.element.ElementKind;
14 | import javax.lang.model.element.ExecutableElement;
15 | import javax.lang.model.element.VariableElement;
16 | import javax.lang.model.type.DeclaredType;
17 | import javax.lang.model.type.MirroredTypeException;
18 | import javax.lang.model.type.TypeKind;
19 | import javax.lang.model.type.TypeMirror;
20 | import javax.lang.model.util.Elements;
21 | import javax.lang.model.util.Types;
22 |
23 | // TODO refactor this class in interfaces and sublacsses for BaggerAnnotated, normal and Generic fields
24 |
25 | /**
26 | * Scans a field and collects information for the java code generating process
27 | *
28 | * @author Hannes Dorfmann
29 | */
30 | public class ParcelableField {
31 |
32 | private String fieldName;
33 | private String type;
34 | private Element element;
35 | private FieldCodeGen codeGenerator;
36 | private TypeMirror genericsTypeArgument;
37 | private String baggerFullyQualifiedName;
38 |
39 | public ParcelableField(VariableElement element, Elements elementUtils, Types typeUtils) {
40 |
41 | this.element = element;
42 | fieldName = element.getSimpleName().toString();
43 | type = element.asType().toString();
44 |
45 | // Check for Bagger
46 | Bagger baggerAnnotation = element.getAnnotation(Bagger.class);
47 | if (baggerAnnotation != null) {
48 | // has a bagger annotation
49 | try {
50 | Class extends ParcelBagger> clazz = baggerAnnotation.value();
51 | baggerFullyQualifiedName = getFullQualifiedNameByClass(clazz);
52 | } catch (MirroredTypeException mte) {
53 | TypeMirror baggerClass = mte.getTypeMirror();
54 | baggerFullyQualifiedName = getFullQualifiedNameByTypeMirror(baggerClass);
55 | }
56 |
57 | // Everything is fine, so use the bagger
58 | codeGenerator = new BaggerCodeGen();
59 | } else {
60 | // Not using Bagger
61 | CodeGenInfo res = SupportedTypes.getCodeGenInfo(element, elementUtils, typeUtils);
62 | codeGenerator = res.getCodeGenerator();
63 | genericsTypeArgument = res.getGenericsType();
64 |
65 | // Check if type is supported
66 | if (codeGenerator == null) {
67 | ProcessorMessage.error(element,
68 | "Unsupported type %s for field %s. You could use @%s to provide your own serialization mechanism",
69 | element.asType().toString(), element.getSimpleName(), Bagger.class.getSimpleName());
70 | }
71 | }
72 | }
73 |
74 | private String getFullQualifiedNameByClass(Class extends ParcelBagger> clazz) {
75 |
76 | // Check public
77 | if (!Modifier.isPublic(clazz.getModifiers())) {
78 |
79 | ProcessorMessage.error(element, "The %s must be a public class to be a valid Bagger",
80 | clazz.getCanonicalName());
81 | return null;
82 | }
83 |
84 | // Check constructors
85 | Constructor>[] constructors = clazz.getConstructors();
86 |
87 | boolean foundDefaultConstructor = false;
88 | for (Constructor c : constructors) {
89 | boolean isPublicConstructor = Modifier.isPublic(c.getModifiers());
90 | Class>[] pType = c.getParameterTypes();
91 |
92 | if (pType.length == 0 && isPublicConstructor) {
93 | foundDefaultConstructor = true;
94 | break;
95 | }
96 | }
97 |
98 | if (!foundDefaultConstructor) {
99 | ProcessorMessage.error(element, "The %s must provide a public empty default constructor",
100 | clazz.getCanonicalName());
101 | return null;
102 | }
103 |
104 | return clazz.getCanonicalName();
105 | }
106 |
107 | /**
108 | * Checks if a class is public
109 | */
110 | private boolean isPublicClass(DeclaredType type) {
111 | Element element = type.asElement();
112 |
113 | return element.getModifiers().contains(javax.lang.model.element.Modifier.PUBLIC);
114 | }
115 |
116 | /**
117 | * Checks if an public empty constructor is available
118 | */
119 | private boolean hasPublicEmptyConstructor(DeclaredType type) {
120 | Element element = type.asElement();
121 |
122 | List extends Element> containing = element.getEnclosedElements();
123 |
124 | for (Element e : containing) {
125 | if (e.getKind() == ElementKind.CONSTRUCTOR) {
126 | ExecutableElement c = (ExecutableElement) e;
127 |
128 | if ((c.getParameters() == null || c.getParameters().isEmpty()) && c.getModifiers()
129 | .contains(javax.lang.model.element.Modifier.PUBLIC)) {
130 | return true;
131 | }
132 | }
133 | }
134 |
135 | return false;
136 | }
137 |
138 | private String getFullQualifiedNameByTypeMirror(TypeMirror baggerClass) {
139 | if (baggerClass == null) {
140 | ProcessorMessage.error(element, "Could not get the bagger class");
141 | return null;
142 | }
143 |
144 | if (baggerClass.getKind() != TypeKind.DECLARED) {
145 | ProcessorMessage.error(element, "@ %s is not a class in %s ", Bagger.class.getSimpleName(),
146 | element.getSimpleName());
147 | return null;
148 | }
149 |
150 | if (!isPublicClass((DeclaredType) baggerClass)) {
151 | ProcessorMessage.error(element, "The %s must be a public class to be a valid Bagger",
152 | baggerClass.toString());
153 | return null;
154 | }
155 |
156 | // Check if the bagger class has a default constructor
157 | if (!hasPublicEmptyConstructor((DeclaredType) baggerClass)) {
158 | ProcessorMessage.error(element,
159 | "The %s must provide a public empty default constructor to be a valid Bagger",
160 | baggerClass.toString());
161 | return null;
162 | }
163 |
164 | return baggerClass.toString();
165 | }
166 |
167 | public Element getElement() {
168 | return element;
169 | }
170 |
171 | public String getFieldName() {
172 | return fieldName;
173 | }
174 |
175 | public String getType() {
176 | return type;
177 | }
178 |
179 | public String getFullQualifiedBaggerName() {
180 | return baggerFullyQualifiedName;
181 | }
182 |
183 | public FieldCodeGen getCodeGenerator() {
184 | return codeGenerator;
185 | }
186 |
187 | public TypeMirror getGenericsTypeArgument() {
188 | return genericsTypeArgument;
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/ParcelablePleaseProcessor.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor;
2 |
3 | import com.hannesdorfmann.parcelableplease.annotation.ParcelableNoThanks;
4 | import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
5 | import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
6 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 | import java.util.Set;
10 | import javax.annotation.processing.AbstractProcessor;
11 | import javax.annotation.processing.Filer;
12 | import javax.annotation.processing.ProcessingEnvironment;
13 | import javax.annotation.processing.RoundEnvironment;
14 | import javax.annotation.processing.SupportedAnnotationTypes;
15 | import javax.lang.model.SourceVersion;
16 | import javax.lang.model.element.Element;
17 | import javax.lang.model.element.ElementKind;
18 | import javax.lang.model.element.Modifier;
19 | import javax.lang.model.element.TypeElement;
20 | import javax.lang.model.element.VariableElement;
21 | import javax.lang.model.util.Elements;
22 | import javax.lang.model.util.Types;
23 |
24 | /**
25 | * @author Hannes Dorfmann
26 | */
27 | @SupportedAnnotationTypes("com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease")
28 | public class ParcelablePleaseProcessor extends AbstractProcessor {
29 |
30 | private static boolean BAGGERS_CREATED = false;
31 |
32 | private Elements elementUtils;
33 | private Types typeUtils;
34 | private Filer filer;
35 |
36 | @Override
37 | public synchronized void init(ProcessingEnvironment env) {
38 | super.init(env);
39 |
40 | elementUtils = env.getElementUtils();
41 | typeUtils = env.getTypeUtils();
42 | filer = env.getFiler();
43 | ProcessorMessage.init(env);
44 | }
45 |
46 | @Override
47 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment env) {
48 |
49 | Element lastElement = null;
50 | CodeGenerator codeGenerator = new CodeGenerator(elementUtils, filer);
51 |
52 | for (Element element : env.getElementsAnnotatedWith(ParcelablePlease.class)) {
53 |
54 | if (!isClass(element)) {
55 | continue;
56 | }
57 |
58 | List fields = new ArrayList();
59 |
60 | lastElement = element;
61 |
62 | ParcelablePlease annotation = element.getAnnotation(ParcelablePlease.class);
63 | boolean allFields = annotation.allFields();
64 | boolean ignorePrivateFields = annotation.ignorePrivateFields();
65 |
66 | List extends Element> memberFields = elementUtils.getAllMembers((TypeElement) element);
67 |
68 | if (memberFields != null) {
69 | for (Element member : memberFields) {
70 | // Search for fields
71 |
72 | if (member.getKind() != ElementKind.FIELD || !(member instanceof VariableElement)) {
73 | continue; // Not a field, so go on
74 | }
75 |
76 | // it's a field, so go on
77 |
78 | ParcelableNoThanks skipFieldAnnotation = member.getAnnotation(ParcelableNoThanks.class);
79 | if (skipFieldAnnotation != null) {
80 | // Field is marked as not parcelabel, so continue with the next
81 | continue;
82 | }
83 |
84 | if (!allFields) {
85 | ParcelableThisPlease fieldAnnotated = member.getAnnotation(ParcelableThisPlease.class);
86 | if (fieldAnnotated == null) {
87 | // Not all fields should parcelable,
88 | // and this field is not annotated as parcelable, so skip this field
89 | continue;
90 | }
91 | }
92 |
93 | // Check the visibility of the field and modifiers
94 | Set modifiers = member.getModifiers();
95 |
96 | if (modifiers.contains(Modifier.STATIC)) {
97 | // Static fields are skipped
98 | continue;
99 | }
100 |
101 | if (modifiers.contains(Modifier.PRIVATE)) {
102 |
103 | if (ignorePrivateFields) {
104 | continue;
105 | }
106 |
107 | ProcessorMessage.error(member,
108 | "The field %s in %s is private. At least default package visibility is required "
109 | + "or annotate this field as not been parcelable with @%s "
110 | + "or configure this class to ignore private fields "
111 | + "with @%s( ignorePrivateFields = true )", member.getSimpleName(),
112 | element.getSimpleName(), ParcelableNoThanks.class.getSimpleName(),
113 | ParcelablePlease.class.getSimpleName());
114 | }
115 |
116 | if (modifiers.contains(Modifier.FINAL)) {
117 | ProcessorMessage.error(member,
118 | "The field %s in %s is final. Final can not be Parcelable", element.getSimpleName(),
119 | member.getSimpleName());
120 | }
121 |
122 | // If we are here the field is be parcelable
123 | fields.add(new ParcelableField((VariableElement) member, elementUtils, typeUtils));
124 | }
125 | }
126 |
127 | //
128 | // Generate the code
129 | //
130 |
131 | try {
132 | codeGenerator.generate((TypeElement) element, fields);
133 | } catch (Exception e) {
134 | e.printStackTrace();
135 | ProcessorMessage.error(lastElement, "An error has occurred while processing %s : %s",
136 | element.getSimpleName(), e.getMessage());
137 | }
138 |
139 | } // End for loop
140 |
141 | return true;
142 | }
143 |
144 | @Override
145 | public SourceVersion getSupportedSourceVersion() {
146 | return SourceVersion.latestSupported();
147 | }
148 |
149 | /**
150 | * Checks if the element is a class
151 | */
152 | private boolean isClass(Element element) {
153 | if (element.getKind() == ElementKind.CLASS) {
154 |
155 | if (element.getModifiers().contains(Modifier.ABSTRACT)) {
156 | ProcessorMessage.error(element,
157 | "Element %s is annotated with @%s but is an abstract class. "
158 | + "Abstract classes can not be annotated. Annotate the concrete class "
159 | + "that implements all abstract methods with @%s", element.getSimpleName(),
160 | ParcelablePlease.class.getSimpleName(), ParcelablePlease.class.getSimpleName());
161 | return false;
162 | }
163 |
164 | if (element.getModifiers().contains(Modifier.PRIVATE)) {
165 | ProcessorMessage.error(element, "The private class %s is annotated with @%s. "
166 | + "Private classes are not supported because of lacking visibility.",
167 | element.getSimpleName(), ParcelablePlease.class.getSimpleName());
168 | return false;
169 | }
170 |
171 | // Ok, its a valid class
172 | return true;
173 | } else {
174 | ProcessorMessage.error(element,
175 | "Element %s is annotated with @%s but is not a class. Only Classes are supported",
176 | element.getSimpleName(), ParcelablePlease.class.getSimpleName());
177 | return false;
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/ProcessorMessage.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor;
2 |
3 | import javax.annotation.processing.ProcessingEnvironment;
4 | import javax.lang.model.element.Element;
5 | import javax.tools.Diagnostic;
6 |
7 | /**
8 | * This is a simple static helper class to print error, waring or note messages during annotation
9 | * processing.
You must initialize this class by calling {@link
10 | * #init(ProcessingEnvironment)} before you can use the messaging methods
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | public class ProcessorMessage {
15 |
16 | private static ProcessingEnvironment processingEnvironment;
17 |
18 | private ProcessorMessage(ProcessingEnvironment processingEnvironment) {
19 | this.processingEnvironment = processingEnvironment;
20 | }
21 |
22 | public static void init(ProcessingEnvironment processingEnv) {
23 | processingEnvironment = processingEnv;
24 | }
25 |
26 | public static void error(Element element, String message, Object... args) {
27 | if (args.length > 0) {
28 | message = String.format(message, args);
29 | }
30 | processingEnvironment.getMessager().printMessage(Diagnostic.Kind.ERROR, message, element);
31 | }
32 |
33 | public static void warn(Element element, String message, Object... args) {
34 | if (args.length > 0) {
35 | message = String.format(message, args);
36 | }
37 | processingEnvironment.getMessager().printMessage(Diagnostic.Kind.WARNING, message, element);
38 | }
39 |
40 | public static void note(Element element, String message, Object... args) {
41 | if (args.length > 0) {
42 | message = String.format(message, args);
43 | }
44 | processingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE, message, element);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/AbsCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import java.io.IOException;
5 | import repacked.com.squareup.javawriter.JavaWriter;
6 |
7 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
8 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
10 |
11 | /**
12 | * @author Hannes Dorfmann
13 | */
14 | public class AbsCodeGen implements FieldCodeGen {
15 |
16 | protected String methodSuffix;
17 |
18 | public AbsCodeGen(String methodSuffix) {
19 | this.methodSuffix = methodSuffix;
20 | }
21 |
22 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter javaWriter)
23 | throws IOException {
24 |
25 | javaWriter.emitStatement("%s.write%s(%s.%s)", PARAM_PARCEL, methodSuffix, PARAM_SOURCE,
26 | field.getFieldName());
27 | }
28 |
29 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter javaWriter)
30 | throws IOException {
31 |
32 | javaWriter.emitStatement("%s.%s = %s.read%s()", PARAM_TARGET, field.getFieldName(), PARAM_PARCEL, methodSuffix);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/BaggerCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import java.io.IOException;
5 | import repacked.com.squareup.javawriter.JavaWriter;
6 |
7 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_FLAGS;
8 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
11 |
12 | /**
13 | * A code generator for Baggers.
14 | *
15 | * @author Hannes Dorfmann
16 | */
17 | public class BaggerCodeGen implements FieldCodeGen {
18 |
19 | public BaggerCodeGen() {
20 |
21 | }
22 |
23 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
24 | throws IOException {
25 |
26 | jw.emitStatement("new %s().write(%s.%s, %s, %s)", field.getFullQualifiedBaggerName(),
27 | PARAM_SOURCE, field.getFieldName(), PARAM_PARCEL, PARAM_FLAGS);
28 | }
29 |
30 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
31 | throws IOException {
32 |
33 | jw.emitStatement("%s.%s = new %s().read(%s)", PARAM_TARGET, field.getFieldName(),
34 | field.getFullQualifiedBaggerName(), PARAM_PARCEL);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/CodeGenerator.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator;
2 |
3 | import com.hannesdorfmann.parcelableplease.annotation.Bagger;
4 | import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
5 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
6 | import com.hannesdorfmann.parcelableplease.processor.ProcessorMessage;
7 | import com.hannesdorfmann.parcelableplease.processor.util.TypeUtils;
8 | import java.io.IOException;
9 | import java.io.Writer;
10 | import java.util.EnumSet;
11 | import java.util.List;
12 | import javax.annotation.processing.Filer;
13 | import javax.lang.model.element.Modifier;
14 | import javax.lang.model.element.TypeElement;
15 | import javax.lang.model.util.Elements;
16 | import javax.tools.JavaFileObject;
17 | import repacked.com.squareup.javawriter.JavaWriter;
18 |
19 | /**
20 | * Generates the javacode for each field
21 | *
22 | * @author Hannes Dorfmann
23 | */
24 | public class CodeGenerator {
25 |
26 | public static final String PARAM_TARGET = "target";
27 |
28 | public static final String PARAM_SOURCE = "source";
29 |
30 | public static final String PARAM_FLAGS = "flags";
31 |
32 | /**
33 | * The parameter name for the
34 | */
35 | public static final String PARAM_PARCEL = "parcel";
36 |
37 | private Filer filer;
38 | private Elements elementUtils;
39 |
40 | public CodeGenerator(Elements elementUtils, Filer filer) {
41 | this.filer = filer;
42 | this.elementUtils = elementUtils;
43 | }
44 |
45 | public void generate(TypeElement classElement, List fields) throws Exception {
46 |
47 | String classSuffix = "ParcelablePlease";
48 | String packageName = TypeUtils.getPackageName(elementUtils, classElement);
49 | String binaryName = TypeUtils.getBinaryName(elementUtils, classElement);
50 | String originFullQualifiedName = classElement.getQualifiedName().toString();
51 | String className;
52 | if (packageName.length() > 0) {
53 | className = binaryName.substring(packageName.length() + 1) + classSuffix;
54 | } else {
55 | className = binaryName + classSuffix;
56 | }
57 | String qualifiedName = binaryName + classSuffix;
58 |
59 | //
60 | // Write code
61 | //
62 |
63 | JavaFileObject jfo = filer.createSourceFile(qualifiedName, classElement);
64 | Writer writer = jfo.openWriter();
65 | JavaWriter jw = new JavaWriter(writer);
66 |
67 | jw.emitPackage(packageName);
68 | jw.emitImports("android.os.Parcel");
69 | jw.emitEmptyLine();
70 | jw.emitJavadoc("Generated class by @%s . Do not modify this code!",
71 | ParcelablePlease.class.getSimpleName());
72 | jw.beginType(className, "class", EnumSet.of(Modifier.PUBLIC));
73 | jw.emitEmptyLine();
74 |
75 | generateWriteToParcel(jw, originFullQualifiedName, fields);
76 | jw.emitEmptyLine();
77 | generateReadFromParcel(jw, originFullQualifiedName, fields);
78 |
79 | jw.endType();
80 | jw.close();
81 | }
82 |
83 | /**
84 | * Generate the writeToParcel method
85 | *
86 | * @throws IOException
87 | */
88 | private void generateWriteToParcel(JavaWriter jw, String originClass,
89 | List fields) throws IOException {
90 |
91 | jw.beginMethod("void", "writeToParcel", EnumSet.of(Modifier.PUBLIC, Modifier.STATIC),
92 | originClass, PARAM_SOURCE, "Parcel", PARAM_PARCEL, "int", PARAM_FLAGS);
93 |
94 | for (ParcelableField field : fields) {
95 | FieldCodeGen gen = field.getCodeGenerator();
96 |
97 | if (gen == null) { // Already checked before, but let's check it again
98 | ProcessorMessage.error(field.getElement(),
99 | "The field %s is not Parcelable or of unsupported type. Use a @%s",
100 | field.getFieldName(),
101 | Bagger.class.getSimpleName() + " to provide your own serialisation mechanism");
102 |
103 | throw new IOException("Unparcelable Field " + field.getFieldName());
104 | }
105 |
106 | jw.emitEmptyLine();
107 | gen.generateWriteToParcel(field, jw);
108 | }
109 |
110 | jw.endMethod();
111 | }
112 |
113 | private void generateReadFromParcel(JavaWriter jw, String originClass,
114 | List fields) throws IOException {
115 |
116 | jw.beginMethod("void", "readFromParcel", EnumSet.of(Modifier.PUBLIC, Modifier.STATIC),
117 | originClass, PARAM_TARGET, "Parcel", PARAM_PARCEL);
118 |
119 | for (ParcelableField field : fields) {
120 | FieldCodeGen gen = field.getCodeGenerator();
121 |
122 | if (gen == null) { // Already checked before, but let's check it again
123 | ProcessorMessage.error(field.getElement(),
124 | "The field %s is not Parcelable or of unsupported type. Use a @%s",
125 | field.getFieldName(),
126 | Bagger.class.getSimpleName() + " to provide your own serialisation mechanism");
127 |
128 | throw new IOException("Unparcelable Field " + field.getFieldName());
129 | }
130 |
131 | jw.emitEmptyLine();
132 | gen.generateReadFromParcel(field, jw);
133 | }
134 |
135 | jw.endMethod();
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/FieldCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import java.io.IOException;
5 | import repacked.com.squareup.javawriter.JavaWriter;
6 |
7 | /**
8 | * @author Hannes Dorfmann
9 | */
10 | public interface FieldCodeGen {
11 |
12 | public void generateWriteToParcel(ParcelableField field, JavaWriter javaWriter)
13 | throws IOException;
14 |
15 | public void generateReadFromParcel(ParcelableField field, JavaWriter javaWriter)
16 | throws IOException;
17 | }
18 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/SupportedTypes.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator;
2 |
3 | import com.hannesdorfmann.parcelableplease.annotation.Bagger;
4 | import com.hannesdorfmann.parcelableplease.processor.ProcessorMessage;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.android.BundleCodeGen;
6 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.android.ParcelableCodeGen;
7 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.android.SparseBooleanCodeGen;
8 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.collection.AbsListCodeGen;
9 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.collection.ParcelableArrayCodeGen;
10 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.collection.PrimitiveArrayCodeGen;
11 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.collection.StringListCodeGen;
12 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.other.DateCodeGen;
13 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.other.SerializeableCodeGen;
14 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.primitives.BooleanCodeGen;
15 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.primitiveswrapper.AbsPrimitiveWrapperCodeGen;
16 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.primitiveswrapper.BooleanWrapperCodeGen;
17 | import com.hannesdorfmann.parcelableplease.processor.util.CodeGenInfo;
18 | import java.util.ArrayList;
19 | import java.util.Date;
20 | import java.util.HashMap;
21 | import java.util.LinkedList;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.concurrent.CopyOnWriteArrayList;
25 | import javax.lang.model.element.Element;
26 | import javax.lang.model.element.TypeElement;
27 | import javax.lang.model.element.VariableElement;
28 | import javax.lang.model.type.ArrayType;
29 | import javax.lang.model.type.DeclaredType;
30 | import javax.lang.model.type.TypeKind;
31 | import javax.lang.model.type.TypeMirror;
32 | import javax.lang.model.util.Elements;
33 | import javax.lang.model.util.Types;
34 |
35 | /**
36 | * The supported types and the corresponding code generator classes
37 | *
38 | * @author Hannes Dorfmann
39 | */
40 | public class SupportedTypes {
41 |
42 | private static final String TYPE_KEY_PARCELABLE = "android.os.Parcelable";
43 | private static final String TYPE_KEY_SERIALIZABLE = "java.io.Serializable";
44 | private static final String TYPE_KEY_PARCELABLE_ARRAYLIST = "Parcelable-ArrayList";
45 | private static final String TYPE_KEY_PARCELABLE_LINKEDLIST = "Parcelable-LinkedList";
46 | private static final String TYPE_KEY_PARCELABLE_LIST = "Parcelable-List";
47 | private static final String TYPE_KEY_STRING_LIST = "String-List";
48 | private static final String TYPE_KEY_BUNDLE = "android.os.Bundle";
49 | private static final String TYPE_KEY_DOUBLE_ARRAY = "Array-Double";
50 | private static final String TYPE_KEY_FLOAT_ARRAY = "Array-Float";
51 | private static final String TYPE_KEY_INT_ARRAY = "Array-Int";
52 | private static final String TYPE_KEY_BOOL_ARRAY = "Array-Boolean";
53 | private static final String TYPE_KEY_BYTE_ARRAY = "Array-Byte";
54 | private static final String TYPE_KEY_CHAR_ARRAY = "Array-Char";
55 | private static final String TYPE_KEY_LONG_ARRAY = "Array-Long";
56 | private static final String TYPE_KEY_STRING_ARRAY = "Array-String";
57 | private static final String TYPE_KEY_PARCELABLE_ARRAY = "Array-Parcelable";
58 | private static final String TYPE_KEY_SPARSE_BOOLEAN_ARRAY = "android.util.SparseBooleanArray";
59 | private static final String TYPE_KEY_SPARSE_ARRAY = "android.util.SparseArray";
60 |
61 | private static final String TYPE_KEY_PARCELABLE_COPYONWRITEARRAYLIST =
62 | "Parcelable-CopyOnWriteArrayList";
63 |
64 | private static Map typeMap;
65 |
66 | static {
67 | typeMap = new HashMap();
68 |
69 | // primitives
70 | typeMap.put(byte.class.getCanonicalName(), new AbsCodeGen("Byte"));
71 | typeMap.put(boolean.class.getCanonicalName(), new BooleanCodeGen());
72 | typeMap.put(double.class.getCanonicalName(), new AbsCodeGen("Double"));
73 | typeMap.put(float.class.getCanonicalName(), new AbsCodeGen("Float"));
74 | typeMap.put(int.class.getCanonicalName(), new AbsCodeGen("Int"));
75 | typeMap.put(long.class.getCanonicalName(), new AbsCodeGen("Long"));
76 | typeMap.put(String.class.getCanonicalName(), new AbsCodeGen("String"));
77 |
78 | // Wrapper classes
79 | typeMap.put(Byte.class.getCanonicalName(), new AbsPrimitiveWrapperCodeGen("Byte"));
80 | typeMap.put(Boolean.class.getCanonicalName(), new BooleanWrapperCodeGen());
81 | typeMap.put(Double.class.getCanonicalName(), new AbsPrimitiveWrapperCodeGen("Double"));
82 | typeMap.put(Float.class.getCanonicalName(), new AbsPrimitiveWrapperCodeGen("Float"));
83 | typeMap.put(Integer.class.getCanonicalName(), new AbsPrimitiveWrapperCodeGen("Int"));
84 | typeMap.put(Long.class.getCanonicalName(), new AbsPrimitiveWrapperCodeGen("Long"));
85 |
86 | // Android
87 | typeMap.put(TYPE_KEY_PARCELABLE, new ParcelableCodeGen());
88 | typeMap.put(TYPE_KEY_BUNDLE, new BundleCodeGen());
89 | typeMap.put(TYPE_KEY_SPARSE_BOOLEAN_ARRAY, new SparseBooleanCodeGen());
90 | // typeMap.put(TYPE_KEY_SPARSE_ARRAY, new SparseArrayCodeGen()); // TODO implement
91 |
92 | // Lists
93 | typeMap.put(TYPE_KEY_STRING_LIST, new StringListCodeGen());
94 | typeMap.put(TYPE_KEY_PARCELABLE_LIST, new AbsListCodeGen(ArrayList.class.getName()));
95 | typeMap.put(TYPE_KEY_PARCELABLE_ARRAYLIST, new AbsListCodeGen(ArrayList.class.getName()));
96 | typeMap.put(TYPE_KEY_PARCELABLE_LINKEDLIST, new AbsListCodeGen(LinkedList.class.getName()));
97 | typeMap.put(TYPE_KEY_PARCELABLE_COPYONWRITEARRAYLIST,
98 | new AbsListCodeGen(CopyOnWriteArrayList.class.getName()));
99 |
100 | // Arrays
101 | typeMap.put(TYPE_KEY_BOOL_ARRAY, new PrimitiveArrayCodeGen("BooleanArray", "boolean"));
102 | typeMap.put(TYPE_KEY_BYTE_ARRAY, new PrimitiveArrayCodeGen("ByteArray", "byte"));
103 | typeMap.put(TYPE_KEY_CHAR_ARRAY, new PrimitiveArrayCodeGen("CharArray", "char"));
104 | typeMap.put(TYPE_KEY_DOUBLE_ARRAY, new PrimitiveArrayCodeGen("DoubleArray", "double"));
105 | typeMap.put(TYPE_KEY_FLOAT_ARRAY, new PrimitiveArrayCodeGen("FloatArray", "float"));
106 | typeMap.put(TYPE_KEY_LONG_ARRAY, new PrimitiveArrayCodeGen("LongArray", "long"));
107 | typeMap.put(TYPE_KEY_INT_ARRAY, new PrimitiveArrayCodeGen("IntArray", "int"));
108 | typeMap.put(TYPE_KEY_STRING_ARRAY, new PrimitiveArrayCodeGen("StringArray", "String"));
109 | typeMap.put(TYPE_KEY_PARCELABLE_ARRAY, new ParcelableArrayCodeGen());
110 |
111 | // Other common classes
112 | typeMap.put(TYPE_KEY_SERIALIZABLE, new SerializeableCodeGen());
113 | typeMap.put(Date.class.getCanonicalName(), new DateCodeGen());
114 | }
115 |
116 | /**
117 | * Collect information about the element and the corresponding code generator
118 | */
119 | public static CodeGenInfo getCodeGenInfo(VariableElement element, Elements elements,
120 | Types types) {
121 |
122 | // Special classes, primitive, wrappers, etc.
123 | String typeKey = element.asType().toString();
124 | if (typeMap.get(typeKey) != null) {
125 | return new CodeGenInfo(typeMap.get(typeKey));
126 | }
127 |
128 | // Check if its a simple parcelable
129 | if (isOfType(element, "android.os.Parcelable", elements, types)) {
130 | return new CodeGenInfo(typeMap.get(TYPE_KEY_PARCELABLE));
131 | }
132 |
133 | // Lists
134 | if (isOfWildCardType(element, ArrayList.class.getName(), "android.os.Parcelable", elements,
135 | types)) {
136 |
137 | return new CodeGenInfo(typeMap.get(TYPE_KEY_PARCELABLE_ARRAYLIST),
138 | hasGenericsTypeArgumentOf(element, "android.os.Parcelable", elements, types));
139 | }
140 |
141 | if (isOfWildCardType(element, LinkedList.class.getName(), "android.os.Parcelable", elements,
142 | types)) {
143 | return new CodeGenInfo(typeMap.get(TYPE_KEY_PARCELABLE_LINKEDLIST),
144 | hasGenericsTypeArgumentOf(element, "android.os.Parcelable", elements, types));
145 | }
146 |
147 | if (isOfWildCardType(element, CopyOnWriteArrayList.class.getName(), "android.os.Parcelable",
148 | elements, types)) {
149 | return new CodeGenInfo(typeMap.get(TYPE_KEY_PARCELABLE_COPYONWRITEARRAYLIST),
150 | hasGenericsTypeArgumentOf(element, "android.os.Parcelable", elements, types));
151 | }
152 |
153 | if (isOfWildCardType(element, List.class.getName(), "android.os.Parcelable", elements, types)) {
154 | return new CodeGenInfo(typeMap.get(TYPE_KEY_PARCELABLE_LIST),
155 | hasGenericsTypeArgumentOf(element, "android.os.Parcelable", elements, types));
156 | }
157 |
158 | if (isOfWildCardType(element, List.class.getName(), String.class.getName(), elements, types)) {
159 | return new CodeGenInfo(typeMap.get(TYPE_KEY_STRING_LIST));
160 | }
161 |
162 | // Arrays
163 | if (element.asType().getKind() == TypeKind.ARRAY) {
164 |
165 | ArrayType arrayType = (ArrayType) element.asType();
166 |
167 | TypeMirror arrayOf = arrayType.getComponentType();
168 |
169 | if (arrayOf.getKind() == TypeKind.CHAR) {
170 | return new CodeGenInfo(typeMap.get(TYPE_KEY_CHAR_ARRAY));
171 | }
172 |
173 | if (arrayOf.getKind() == TypeKind.BOOLEAN) {
174 | return new CodeGenInfo(typeMap.get(TYPE_KEY_BOOL_ARRAY));
175 | }
176 |
177 | if (arrayOf.getKind() == TypeKind.BYTE) {
178 | return new CodeGenInfo(typeMap.get(TYPE_KEY_BYTE_ARRAY));
179 | }
180 |
181 | if (arrayOf.getKind() == TypeKind.DOUBLE) {
182 | return new CodeGenInfo(typeMap.get(TYPE_KEY_DOUBLE_ARRAY));
183 | }
184 |
185 | if (arrayOf.getKind() == TypeKind.FLOAT) {
186 | return new CodeGenInfo(typeMap.get(TYPE_KEY_FLOAT_ARRAY));
187 | }
188 |
189 | if (arrayOf.getKind() == TypeKind.INT) {
190 | return new CodeGenInfo(typeMap.get(TYPE_KEY_INT_ARRAY));
191 | }
192 |
193 | if (arrayOf.getKind() == TypeKind.LONG) {
194 | return new CodeGenInfo(typeMap.get(TYPE_KEY_LONG_ARRAY));
195 | }
196 |
197 | if (arrayOf.toString().equals(String.class.getName())) {
198 | return new CodeGenInfo(typeMap.get(TYPE_KEY_STRING_ARRAY));
199 | }
200 |
201 | if (isOfType(arrayOf, "android.os.Parcelable", elements, types)) {
202 | // It's an array of parcelable
203 | return new CodeGenInfo(typeMap.get(TYPE_KEY_PARCELABLE_ARRAY), arrayOf);
204 | }
205 |
206 | // Unsupported Array Type
207 | ProcessorMessage.error(element, "Unsuppored type %s as Array type for field %s. "
208 | + "You could write your own Serialization mechanism by using @%s ",
209 | element.asType().toString(), element.getSimpleName(), Bagger.class.getSimpleName());
210 | }
211 |
212 |
213 | // TODO SparseArray
214 | // if (isOfWildCardType(element, "android.util.SparseArray", "android.os.Parcelable", elements,
215 | // types)) {
216 | // return new CodeGenInfo(typeMap.get(TYPE_KEY_SPARSE_ARRAY),
217 | // hasGenericsTypeArgumentOf(element, null, elements, types));
218 | // }
219 |
220 |
221 | // Serializable as last
222 | if (isOfType(element, "java.io.Serializable", elements, types)) {
223 | return new CodeGenInfo(typeMap.get(TYPE_KEY_SERIALIZABLE));
224 | }
225 |
226 | // Unsupported type
227 | ProcessorMessage.error(element, "Unsuppored type %s for field %s. "
228 | + "You could write your own Serialization mechanism by using @%s ",
229 | element.asType().toString(), element.getSimpleName(), Bagger.class.getSimpleName());
230 |
231 | return new CodeGenInfo(null);
232 | }
233 |
234 | /**
235 | * Get the wildcardType
236 | */
237 | public static TypeMirror getWildcardType(String type, String elementType, Elements elements,
238 | Types types) {
239 | TypeElement arrayList = elements.getTypeElement(type);
240 | TypeMirror elType = elements.getTypeElement(elementType).asType();
241 | return types.getDeclaredType(arrayList, types.getWildcardType(elType, null));
242 | }
243 |
244 | private static boolean isOfWildCardType(Element element, String type, String wildcardtype,
245 | Elements elements, Types types) {
246 | return types.isAssignable(element.asType(),
247 | getWildcardType(type, wildcardtype, elements, types));
248 | }
249 |
250 | private static boolean isOfType(Element element, String type, Elements elements, Types types) {
251 | return isOfType(element.asType(), type, elements, types);
252 | }
253 |
254 | private static boolean isOfType(TypeMirror typeMirror, String type, Elements elements,
255 | Types types) {
256 | return types.isAssignable(typeMirror, elements.getTypeElement(type).asType());
257 | }
258 |
259 | /**
260 | * Checks if the variabel element has generics arguments that matches the expected type
261 | */
262 | public static TypeMirror hasGenericsTypeArgumentOf(Element element, String typeToCheck,
263 | Elements elements, Types types) {
264 |
265 | if (element.asType().getKind() != TypeKind.DECLARED
266 | || !(element.asType() instanceof DeclaredType)) {
267 | ProcessorMessage.error(element, "The field %s in %s doesn't have generic type arguments!",
268 | element.getSimpleName(), element.asType().toString());
269 | }
270 |
271 | DeclaredType declaredType = (DeclaredType) element.asType();
272 | List extends TypeMirror> typeArguments = declaredType.getTypeArguments();
273 |
274 | if (typeArguments.isEmpty()) {
275 | ProcessorMessage.error(element, "The field %s in %s doesn't have generic type arguments!",
276 | element.getSimpleName(), element.asType().toString());
277 | }
278 |
279 | if (typeArguments.size() > 1) {
280 | ProcessorMessage.error(element, "The field %s in %s has more than 1 generic type argument!",
281 | element.getSimpleName(), element.asType().toString());
282 | }
283 |
284 | // Ok it has a generic argument, check if this extends Parcelable
285 | TypeMirror argument = typeArguments.get(0);
286 |
287 | if (typeToCheck != null) {
288 | if (!isOfType(argument, typeToCheck, elements, types)) {
289 | ProcessorMessage.error(element,
290 | "The fields %s generic type argument is not of type %s! (in %s )",
291 | element.getSimpleName(), typeToCheck, element.asType().toString());
292 | }
293 | }
294 |
295 | // everything is like expected
296 | return argument;
297 | }
298 | }
299 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/android/BundleCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.android;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.AbsCodeGen;
4 |
5 | /**
6 | * Bundle code generator
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | public class BundleCodeGen extends AbsCodeGen {
11 |
12 | public BundleCodeGen() {
13 | super("Bundle");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/android/ParcelableCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.android;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
5 | import java.io.IOException;
6 | import repacked.com.squareup.javawriter.JavaWriter;
7 |
8 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_FLAGS;
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
11 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
12 |
13 | /**
14 | * @author Hannes Dorfmann
15 | */
16 | public class ParcelableCodeGen implements FieldCodeGen {
17 |
18 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter javaWriter)
19 | throws IOException {
20 |
21 | javaWriter.emitStatement("%s.writeParcelable(%s.%s, %s)", PARAM_PARCEL, PARAM_SOURCE,
22 | field.getFieldName(), PARAM_FLAGS);
23 | }
24 |
25 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter javaWriter)
26 | throws IOException {
27 |
28 | javaWriter.emitStatement("%s.%s = %s.readParcelable(%s.class.getClassLoader())", PARAM_TARGET, field.getFieldName(),
29 | PARAM_PARCEL, field.getType());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/android/SparseArrayCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.android;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
5 | import java.io.IOException;
6 | import repacked.com.squareup.javawriter.JavaWriter;
7 |
8 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
11 |
12 | /**
13 | * @author Hannes Dorfmann
14 | */
15 | public class SparseArrayCodeGen implements FieldCodeGen {
16 |
17 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter javaWriter)
18 | throws IOException {
19 |
20 | javaWriter.emitStatement("%s.writeSparseArray(%s.%s)", PARAM_PARCEL, PARAM_SOURCE,
21 | field.getFieldName());
22 | }
23 |
24 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter javaWriter)
25 | throws IOException {
26 |
27 | javaWriter.emitStatement("%s.%s = %s.readSparseArray(%s.class.getClassLoader())", PARAM_TARGET,
28 | field.getFieldName(), PARAM_PARCEL, field.getGenericsTypeArgument().toString());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/android/SparseBooleanCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.android;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.AbsCodeGen;
4 |
5 | /**
6 | * SparseBooleanArray
7 | *
8 | * @author Hannes Dorfmann
9 | */
10 | public class SparseBooleanCodeGen extends AbsCodeGen {
11 |
12 | public SparseBooleanCodeGen() {
13 | super("SparseBooleanArray");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/collection/AbsListCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.collection;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
6 | import java.io.IOException;
7 | import repacked.com.squareup.javawriter.JavaWriter;
8 |
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
11 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
12 |
13 | /**
14 | * It also handles null values
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | public class AbsListCodeGen implements FieldCodeGen {
19 |
20 | private String listType;
21 |
22 | public AbsListCodeGen(String listType) {
23 | this.listType = listType;
24 | }
25 |
26 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
27 | throws IOException {
28 |
29 | jw.emitStatement("%s.writeByte( (byte) (%s.%s != null ? 1 : 0) )", CodeGenerator.PARAM_PARCEL,
30 | CodeGenerator.PARAM_SOURCE, field.getFieldName());
31 |
32 | jw.beginControlFlow("if (%s.%s != null)", CodeGenerator.PARAM_SOURCE, field.getFieldName());
33 | jw.emitStatement("%s.writeList(%s.%s)", PARAM_PARCEL, PARAM_SOURCE, field.getFieldName());
34 | jw.endControlFlow();
35 | }
36 |
37 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
38 | throws IOException {
39 |
40 | String typeArguments = field.getGenericsTypeArgument().toString();
41 |
42 | jw.emitStatement("boolean %sNullHelper", field.getFieldName());
43 | jw.emitStatement("%sNullHelper = ( %s.readByte() == 1 )", field.getFieldName(),
44 | CodeGenerator.PARAM_PARCEL);
45 |
46 | jw.beginControlFlow("if (%sNullHelper)", field.getFieldName());
47 | jw.emitStatement("%s<%s> %sListHelper = new %s<%s>()", listType, typeArguments,
48 | field.getFieldName(), listType, typeArguments);
49 | jw.emitStatement("%s.readList(%sListHelper, %s.class.getClassLoader())", PARAM_PARCEL,
50 | field.getFieldName(), typeArguments);
51 | jw.emitStatement("%s.%s = %sListHelper", PARAM_TARGET, field.getFieldName(),
52 | field.getFieldName());
53 | jw.nextControlFlow("else");
54 | jw.emitStatement("%s.%s = null", PARAM_TARGET, field.getFieldName());
55 | jw.endControlFlow();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/collection/ParcelableArrayCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.collection;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
5 | import java.io.IOException;
6 | import repacked.com.squareup.javawriter.JavaWriter;
7 |
8 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_FLAGS;
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
11 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
12 |
13 | /**
14 | * Parcelable array
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | public class ParcelableArrayCodeGen implements FieldCodeGen {
19 |
20 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
21 | throws IOException {
22 |
23 | jw.emitStatement("%s.writeParcelableArray(%s.%s, %s)", PARAM_PARCEL, PARAM_SOURCE,
24 | field.getFieldName(), PARAM_FLAGS);
25 | }
26 |
27 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
28 | throws IOException {
29 |
30 | String type = field.getGenericsTypeArgument().toString();
31 |
32 | jw.emitStatement(
33 | "android.os.Parcelable[] %sNullHelper = %s.readParcelableArray(%s.class.getClassLoader())",
34 | field.getFieldName(), PARAM_PARCEL, type);
35 | jw.beginControlFlow("if (%sNullHelper != null)", field.getFieldName());
36 | jw.emitStatement(
37 | "%s.%s = java.util.Arrays.copyOf(%sNullHelper, %sNullHelper.length, %s[].class)",
38 | PARAM_TARGET, field.getFieldName(), field.getFieldName(), field.getFieldName(), type);
39 | jw.nextControlFlow("else");
40 | jw.emitStatement("%s.%s = null", PARAM_TARGET, field.getFieldName());
41 | jw.endControlFlow();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/collection/PrimitiveArrayCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.collection;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
6 | import java.io.IOException;
7 | import repacked.com.squareup.javawriter.JavaWriter;
8 |
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
11 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
12 |
13 | /**
14 | * It also handles null values
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | public class PrimitiveArrayCodeGen implements FieldCodeGen {
19 |
20 | private String methodSuffix;
21 | private String type;
22 |
23 | public PrimitiveArrayCodeGen(String methodSuffix, String type) {
24 | this.methodSuffix = methodSuffix;
25 | this.type = type;
26 | }
27 |
28 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
29 | throws IOException {
30 |
31 | // -1 means that it array is null. Otherwise its array.length
32 |
33 | jw.emitStatement("%s.writeInt( (%s.%s != null ? %s.%s.length : -1) )",
34 | CodeGenerator.PARAM_PARCEL, CodeGenerator.PARAM_SOURCE, field.getFieldName(),
35 | CodeGenerator.PARAM_SOURCE, field.getFieldName());
36 |
37 | jw.beginControlFlow("if (%s.%s != null)", CodeGenerator.PARAM_SOURCE, field.getFieldName());
38 | jw.emitStatement("%s.write%s(%s.%s)", PARAM_PARCEL, methodSuffix, PARAM_SOURCE,
39 | field.getFieldName());
40 | jw.endControlFlow();
41 | }
42 |
43 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
44 | throws IOException {
45 |
46 | jw.emitStatement("int %sLengthHelper = -1", field.getFieldName());
47 | jw.emitStatement("%sLengthHelper = %s.readInt()", field.getFieldName(),
48 | CodeGenerator.PARAM_PARCEL);
49 |
50 | jw.beginControlFlow("if (%sLengthHelper >= 0)", field.getFieldName());
51 | jw.emitStatement("%s[] %sArrayHelper = new %s[%sLengthHelper]", type, field.getFieldName(),
52 | type, field.getFieldName());
53 | jw.emitStatement("%s.read%s(%sArrayHelper)", PARAM_PARCEL, methodSuffix, field.getFieldName());
54 | jw.emitStatement("%s.%s = %sArrayHelper", PARAM_TARGET, field.getFieldName(),
55 | field.getFieldName());
56 | jw.nextControlFlow("else");
57 | jw.emitStatement("%s.%s = null", PARAM_TARGET, field.getFieldName());
58 | jw.endControlFlow();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/collection/StringListCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.collection;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
5 | import repacked.com.squareup.javawriter.JavaWriter;
6 |
7 | import java.io.IOException;
8 |
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.*;
10 |
11 | /**
12 | * String list
13 | *
14 | * @author Yaroslav Heriatovych
15 | */
16 | public class StringListCodeGen implements FieldCodeGen {
17 |
18 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
19 | throws IOException {
20 |
21 | jw.emitStatement("%s.writeStringList(%s.%s)", PARAM_PARCEL, PARAM_SOURCE,
22 | field.getFieldName());
23 | }
24 |
25 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
26 | throws IOException {
27 |
28 | jw.emitStatement("%s.%s = %s.createStringArrayList()", PARAM_TARGET, field.getFieldName(), PARAM_PARCEL);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/other/DateCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.other;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
6 | import java.io.IOException;
7 | import repacked.com.squareup.javawriter.JavaWriter;
8 |
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
11 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
12 |
13 | /**
14 | * It also handles null values
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | public class DateCodeGen implements FieldCodeGen {
19 |
20 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
21 | throws IOException {
22 |
23 | jw.emitStatement("%s.writeByte( (byte) (%s.%s != null ? 1 : 0) )", CodeGenerator.PARAM_PARCEL,
24 | CodeGenerator.PARAM_SOURCE, field.getFieldName());
25 |
26 | jw.beginControlFlow("if (%s.%s != null)", CodeGenerator.PARAM_SOURCE, field.getFieldName());
27 | jw.emitStatement("%s.writeLong(%s.%s.getTime())", PARAM_PARCEL, PARAM_SOURCE,
28 | field.getFieldName());
29 | jw.endControlFlow();
30 | }
31 |
32 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
33 | throws IOException {
34 |
35 | jw.emitStatement("boolean %sNullHelper", field.getFieldName());
36 | jw.emitStatement("%sNullHelper = ( %s.readByte() == 1 )", field.getFieldName(),
37 | CodeGenerator.PARAM_PARCEL);
38 |
39 | jw.beginControlFlow("if (%sNullHelper)", field.getFieldName());
40 | jw.emitStatement("long %sLongHelper = %s.readLong()", field.getFieldName(), PARAM_PARCEL);
41 | jw.emitStatement("%s.%s = new java.util.Date(%sLongHelper)", PARAM_TARGET, field.getFieldName(),
42 | field.getFieldName());
43 | jw.nextControlFlow("else");
44 | jw.emitStatement("%s.%s = null", PARAM_TARGET, field.getFieldName());
45 | jw.endControlFlow();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/other/SerializeableCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.other;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.AbsCodeGen;
5 | import java.io.IOException;
6 | import repacked.com.squareup.javawriter.JavaWriter;
7 |
8 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
10 |
11 | /**
12 | * Code generartor for Serializable
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | public class SerializeableCodeGen extends AbsCodeGen {
17 |
18 | public SerializeableCodeGen() {
19 | super("Serializable");
20 | }
21 |
22 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter javaWriter)
23 | throws IOException {
24 |
25 | javaWriter.emitStatement("%s.%s = (%s) %s.readSerializable()", PARAM_TARGET,
26 | field.getFieldName(), field.getType(), PARAM_PARCEL);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/primitives/BooleanCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.primitives;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
6 | import java.io.IOException;
7 | import repacked.com.squareup.javawriter.JavaWriter;
8 |
9 | /**
10 | * For boolean primitives
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | public class BooleanCodeGen implements FieldCodeGen {
15 |
16 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter javaWriter)
17 | throws IOException {
18 |
19 | javaWriter.emitStatement("%s.writeByte( (byte) (%s.%s? 1 : 0))", CodeGenerator.PARAM_PARCEL,
20 | CodeGenerator.PARAM_SOURCE, field.getFieldName());
21 | }
22 |
23 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter javaWriter)
24 | throws IOException {
25 |
26 | javaWriter.emitStatement("%s.%s = ( %s.readByte() == 1 )", CodeGenerator.PARAM_TARGET,
27 | field.getFieldName(), CodeGenerator.PARAM_PARCEL);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/primitiveswrapper/AbsPrimitiveWrapperCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.primitiveswrapper;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
6 | import java.io.IOException;
7 | import repacked.com.squareup.javawriter.JavaWriter;
8 |
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_PARCEL;
10 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_SOURCE;
11 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
12 |
13 | /**
14 | * It also handles null values
15 | *
16 | * @author Hannes Dorfmann
17 | */
18 | public class AbsPrimitiveWrapperCodeGen implements FieldCodeGen {
19 |
20 | private String methodSuffix;
21 |
22 | public AbsPrimitiveWrapperCodeGen(String methodSuffix) {
23 | this.methodSuffix = methodSuffix;
24 | }
25 |
26 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
27 | throws IOException {
28 |
29 | jw.emitStatement("%s.writeByte( (byte) (%s.%s != null ? 1 : 0) )", CodeGenerator.PARAM_PARCEL,
30 | CodeGenerator.PARAM_SOURCE, field.getFieldName());
31 |
32 | jw.beginControlFlow("if (%s.%s != null)", CodeGenerator.PARAM_SOURCE, field.getFieldName());
33 | jw.emitStatement("%s.write%s(%s.%s)", PARAM_PARCEL, methodSuffix, PARAM_SOURCE,
34 | field.getFieldName());
35 | jw.endControlFlow();
36 | }
37 |
38 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
39 | throws IOException {
40 |
41 | jw.emitStatement("boolean %sNullHelper", field.getFieldName());
42 | jw.emitStatement("%sNullHelper = ( %s.readByte() == 1 )", field.getFieldName(),
43 | CodeGenerator.PARAM_PARCEL);
44 |
45 | jw.beginControlFlow("if (%sNullHelper)", field.getFieldName());
46 | jw.emitStatement("%s.%s = %s.read%s()", PARAM_TARGET, field.getFieldName(), PARAM_PARCEL,
47 | methodSuffix);
48 | jw.nextControlFlow("else");
49 | jw.emitStatement("%s.%s = null", PARAM_TARGET, field.getFieldName());
50 | jw.endControlFlow();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/codegenerator/primitiveswrapper/BooleanWrapperCodeGen.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.codegenerator.primitiveswrapper;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.ParcelableField;
4 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator;
5 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
6 | import java.io.IOException;
7 | import repacked.com.squareup.javawriter.JavaWriter;
8 |
9 | import static com.hannesdorfmann.parcelableplease.processor.codegenerator.CodeGenerator.PARAM_TARGET;
10 |
11 | /**
12 | * It also handles null values
13 | *
14 | * @author Hannes Dorfmann
15 | */
16 | public class BooleanWrapperCodeGen implements FieldCodeGen {
17 |
18 | @Override public void generateWriteToParcel(ParcelableField field, JavaWriter jw)
19 | throws IOException {
20 |
21 | jw.emitStatement("%s.writeByte( (byte) (%s.%s != null ? 1 : 0) )", CodeGenerator.PARAM_PARCEL,
22 | CodeGenerator.PARAM_SOURCE, field.getFieldName());
23 |
24 | jw.beginControlFlow("if (%s.%s != null)", CodeGenerator.PARAM_SOURCE, field.getFieldName());
25 | jw.emitStatement("%s.writeByte( (byte) (%s.%s? 1 : 0))", CodeGenerator.PARAM_PARCEL,
26 | CodeGenerator.PARAM_SOURCE, field.getFieldName());
27 | jw.endControlFlow();
28 | }
29 |
30 | @Override public void generateReadFromParcel(ParcelableField field, JavaWriter jw)
31 | throws IOException {
32 |
33 | jw.emitStatement("boolean %sNullHelper", field.getFieldName());
34 | jw.emitStatement("%sNullHelper = ( %s.readByte() == 1 )", field.getFieldName(),
35 | CodeGenerator.PARAM_PARCEL);
36 |
37 | jw.beginControlFlow("if (%sNullHelper)", field.getFieldName());
38 | jw.emitStatement("%s.%s = ( %s.readByte() == 1 )", CodeGenerator.PARAM_TARGET,
39 | field.getFieldName(), CodeGenerator.PARAM_PARCEL);
40 | jw.nextControlFlow("else");
41 | jw.emitStatement("%s.%s = null", PARAM_TARGET, field.getFieldName());
42 | jw.endControlFlow();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/util/CodeGenInfo.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.util;
2 |
3 | import com.hannesdorfmann.parcelableplease.processor.codegenerator.FieldCodeGen;
4 | import javax.lang.model.type.TypeMirror;
5 |
6 | /**
7 | * A simple class (comparable to a pair) that contains the (see {@link FieldCodeGen} ) and a
8 | * TypeMirror for Generics Type for the same inspected element. Note that Generic Type key can be
9 | * null, or in other words is only available if the inspected element uses generics like
10 | * ArrayList does. In this example the genericsType mirror will be of type Foo.
11 | *
12 | * @author Hannes Dorfmann
13 | */
14 | public class CodeGenInfo {
15 |
16 | private TypeMirror genericsType;
17 |
18 | private FieldCodeGen generator;
19 |
20 | public CodeGenInfo(FieldCodeGen generator) {
21 | this.generator = generator;
22 | }
23 |
24 | public CodeGenInfo(FieldCodeGen generator, TypeMirror genericsType) {
25 | this.generator = generator;
26 | this.genericsType = genericsType;
27 | }
28 |
29 | public FieldCodeGen getCodeGenerator() {
30 | return generator;
31 | }
32 |
33 | public TypeMirror getGenericsType() {
34 | return genericsType;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/processor/src/main/java/com/hannesdorfmann/parcelableplease/processor/util/TypeUtils.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor.util;
2 |
3 | import java.io.IOException;
4 | import java.util.List;
5 | import javax.lang.model.element.Element;
6 | import javax.lang.model.element.PackageElement;
7 | import javax.lang.model.element.TypeElement;
8 | import javax.lang.model.type.TypeMirror;
9 | import javax.lang.model.util.Elements;
10 |
11 | /**
12 | * @author Hannes Dorfmann
13 | */
14 | public class TypeUtils {
15 |
16 | /**
17 | * Checks if a element is of the type
18 | */
19 | public static boolean isTypeOf(Element element, Class> clazz) {
20 | return isTypeOf(element.asType(), clazz);
21 | }
22 |
23 | /**
24 | * Checks if a TypeMirror equals a class
25 | */
26 | public static boolean isTypeOf(TypeMirror type, Class> clazz) {
27 | return type.toString().equals(clazz.getCanonicalName());
28 | }
29 |
30 | /**
31 | * Returns the class this element is part of
32 | */
33 | public static Class> isTypeOf(TypeMirror type, List> classList) {
34 |
35 | for (Class> c : classList) {
36 | if (isTypeOf(type, c)) {
37 | return c;
38 | }
39 | }
40 |
41 | return null;
42 | }
43 |
44 | /**
45 | * Get the Package name
46 | *
47 | * @throws IOException
48 | */
49 | public static String getPackageName(Elements elementUtils, TypeElement type) throws IOException {
50 | PackageElement pkg = elementUtils.getPackageOf(type);
51 | if (!pkg.isUnnamed()) {
52 | return pkg.getQualifiedName().toString();
53 | } else {
54 | return ""; // Default package
55 | }
56 | }
57 |
58 | /**
59 | * Get the qualified name of a class. Also respects innner classes
60 | *
61 | * @param elementUtils Elements
62 | * @param type TypeElement
63 | * @return The qualified name of the class represented by the passed type element
64 | * @throws IOException
65 | */
66 | public static String getBinaryName(Elements elementUtils, TypeElement type) throws IOException {
67 | String packageName = getPackageName(elementUtils, type);
68 | String qualifiedName = type.getQualifiedName().toString();
69 | if (packageName.length() > 0) {
70 | return packageName + '.' + qualifiedName.substring(packageName.length() + 1).replace('.', '$');
71 | } else {
72 | return qualifiedName.replace('.', '$');
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/processor/src/main/java/repacked/com/squareup/javawriter/JavaWriter.java:
--------------------------------------------------------------------------------
1 | // Copyright 2013 Square, Inc.
2 | package repacked.com.squareup.javawriter;
3 |
4 | import java.io.Closeable;
5 | import java.io.IOException;
6 | import java.io.Writer;
7 | import java.lang.annotation.Annotation;
8 | import java.util.ArrayDeque;
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.Collection;
12 | import java.util.Collections;
13 | import java.util.Deque;
14 | import java.util.EnumSet;
15 | import java.util.Iterator;
16 | import java.util.LinkedHashMap;
17 | import java.util.List;
18 | import java.util.Map;
19 | import java.util.Map.Entry;
20 | import java.util.Set;
21 | import java.util.TreeSet;
22 | import java.util.regex.Matcher;
23 | import java.util.regex.Pattern;
24 | import javax.lang.model.element.Modifier;
25 |
26 | import static javax.lang.model.element.Modifier.ABSTRACT;
27 |
28 | /** A utility class which aids in generating Java source files. */
29 | public class JavaWriter implements Closeable {
30 | private static final Pattern TYPE_PATTERN = Pattern.compile("(?:[\\w$]+\\.)*([\\w\\.*$]+)");
31 | private static final int MAX_SINGLE_LINE_ATTRIBUTES = 3;
32 | private static final String INDENT = " ";
33 |
34 | /** Map fully qualified type names to their short names. */
35 | private final Map importedTypes = new LinkedHashMap();
36 |
37 | private String packagePrefix;
38 | private final Deque scopes = new ArrayDeque();
39 | private final Deque types = new ArrayDeque();
40 | private final Writer out;
41 | private boolean isCompressingTypes = true;
42 | private String indent = INDENT;
43 |
44 | /**
45 | * @param out the stream to which Java source will be written. This should be a buffered stream.
46 | */
47 | public JavaWriter(Writer out) {
48 | this.out = out;
49 | }
50 |
51 | public void setCompressingTypes(boolean isCompressingTypes) {
52 | this.isCompressingTypes = isCompressingTypes;
53 | }
54 |
55 | public boolean isCompressingTypes() {
56 | return isCompressingTypes;
57 | }
58 |
59 | public void setIndent(String indent) {
60 | this.indent = indent;
61 | }
62 |
63 | public String getIndent() {
64 | return indent;
65 | }
66 |
67 | /** Emit a package declaration and empty line. */
68 | public JavaWriter emitPackage(String packageName) throws IOException {
69 | if (this.packagePrefix != null) {
70 | throw new IllegalStateException();
71 | }
72 | if (packageName.isEmpty()) {
73 | this.packagePrefix = "";
74 | } else {
75 | out.write("package ");
76 | out.write(packageName);
77 | out.write(";\n\n");
78 | this.packagePrefix = packageName + ".";
79 | }
80 | return this;
81 | }
82 |
83 | /**
84 | * Emit an import for each {@code type} provided. For the duration of the file, all references to
85 | * these classes will be automatically shortened.
86 | */
87 | public JavaWriter emitImports(String... types) throws IOException {
88 | return emitImports(Arrays.asList(types));
89 | }
90 |
91 | /**
92 | * Emit an import for each {@code type} provided. For the duration of the file, all references to
93 | * these classes will be automatically shortened.
94 | */
95 | public JavaWriter emitImports(Class>... types) throws IOException {
96 | List classNames = new ArrayList(types.length);
97 | for (Class> classToImport : types) {
98 | classNames.add(classToImport.getName());
99 | }
100 | return emitImports(classNames);
101 | }
102 |
103 | /**
104 | * Emit an import for each {@code type} in the provided {@code Collection}. For the duration of
105 | * the file, all references to these classes will be automatically shortened.
106 | */
107 | public JavaWriter emitImports(Collection types) throws IOException {
108 | for (String type : new TreeSet(types)) {
109 | Matcher matcher = TYPE_PATTERN.matcher(type);
110 | if (!matcher.matches()) {
111 | throw new IllegalArgumentException(type);
112 | }
113 | if (importedTypes.put(type, matcher.group(1)) != null) {
114 | throw new IllegalArgumentException(type);
115 | }
116 | out.write("import ");
117 | out.write(type);
118 | out.write(";\n");
119 | }
120 | return this;
121 | }
122 |
123 | /**
124 | * Emit a static import for each {@code type} provided. For the duration of the file,
125 | * all references to these classes will be automatically shortened.
126 | */
127 | public JavaWriter emitStaticImports(String... types) throws IOException {
128 | return emitStaticImports(Arrays.asList(types));
129 | }
130 |
131 | /**
132 | * Emit a static import for each {@code type} in the provided {@code Collection}. For the
133 | * duration of the file, all references to these classes will be automatically shortened.
134 | */
135 | public JavaWriter emitStaticImports(Collection types) throws IOException {
136 | for (String type : new TreeSet(types)) {
137 | Matcher matcher = TYPE_PATTERN.matcher(type);
138 | if (!matcher.matches()) {
139 | throw new IllegalArgumentException(type);
140 | }
141 | if (importedTypes.put(type, matcher.group(1)) != null) {
142 | throw new IllegalArgumentException(type);
143 | }
144 | out.write("import static ");
145 | out.write(type);
146 | out.write(";\n");
147 | }
148 | return this;
149 | }
150 |
151 | /**
152 | * Emits a name like {@code java.lang.String} or {@code java.util.List},
153 | * compressing it with imports if possible. Type compression will only be enabled if
154 | * {@link #isCompressingTypes} is true.
155 | */
156 | private JavaWriter emitCompressedType(String type) throws IOException {
157 | if (isCompressingTypes) {
158 | out.write(compressType(type));
159 | } else {
160 | out.write(type);
161 | }
162 | return this;
163 | }
164 |
165 | /** Try to compress a fully-qualified class name to only the class name. */
166 | public String compressType(String type) {
167 | StringBuilder sb = new StringBuilder();
168 | if (this.packagePrefix == null) {
169 | throw new IllegalStateException();
170 | }
171 |
172 | Matcher m = TYPE_PATTERN.matcher(type);
173 | int pos = 0;
174 | while (true) {
175 | boolean found = m.find(pos);
176 |
177 | // Copy non-matching characters like "<".
178 | int typeStart = found ? m.start() : type.length();
179 | sb.append(type, pos, typeStart);
180 |
181 | if (!found) {
182 | break;
183 | }
184 |
185 | // Copy a single class name, shortening it if possible.
186 | String name = m.group(0);
187 | String imported = importedTypes.get(name);
188 | if (imported != null) {
189 | sb.append(imported);
190 | } else if (isClassInPackage(name, packagePrefix)) {
191 | String compressed = name.substring(packagePrefix.length());
192 | if (isAmbiguous(compressed)) {
193 | sb.append(name);
194 | } else {
195 | sb.append(compressed);
196 | }
197 | } else if (isClassInPackage(name, "java.lang.")) {
198 | sb.append(name.substring("java.lang.".length()));
199 | } else {
200 | sb.append(name);
201 | }
202 | pos = m.end();
203 | }
204 | return sb.toString();
205 | }
206 |
207 | private static boolean isClassInPackage(String name, String packagePrefix) {
208 | if (name.startsWith(packagePrefix)) {
209 | if (name.indexOf('.', packagePrefix.length()) == -1) {
210 | return true;
211 | }
212 | // check to see if the part after the package looks like a class
213 | if (Character.isUpperCase(name.charAt(packagePrefix.length()))) {
214 | return true;
215 | }
216 | }
217 | return false;
218 | }
219 |
220 | /**
221 | * Returns true if the imports contain a class with same simple name as {@code compressed}.
222 | *
223 | * @param compressed simple name of the type
224 | */
225 | private boolean isAmbiguous(String compressed) {
226 | return importedTypes.values().contains(compressed);
227 | }
228 |
229 | /**
230 | * Emits an initializer declaration.
231 | *
232 | * @param isStatic true if it should be an static initializer, false for an instance initializer.
233 | */
234 | public JavaWriter beginInitializer(boolean isStatic) throws IOException {
235 | indent();
236 | if (isStatic) {
237 | out.write("static");
238 | out.write(" {\n");
239 | } else {
240 | out.write("{\n");
241 | }
242 | scopes.push(Scope.INITIALIZER);
243 | return this;
244 | }
245 |
246 | /** Ends the current initializer declaration. */
247 | public JavaWriter endInitializer() throws IOException {
248 | popScope(Scope.INITIALIZER);
249 | indent();
250 | out.write("}\n");
251 | return this;
252 | }
253 |
254 | /**
255 | * Emits a type declaration.
256 | *
257 | * @param kind such as "class", "interface" or "enum".
258 | */
259 | public JavaWriter beginType(String type, String kind) throws IOException {
260 | return beginType(type, kind, EnumSet.noneOf(Modifier.class), null);
261 | }
262 |
263 | /**
264 | * Emits a type declaration.
265 | *
266 | * @param kind such as "class", "interface" or "enum".
267 | */
268 | public JavaWriter beginType(String type, String kind, Set modifiers)
269 | throws IOException {
270 | return beginType(type, kind, modifiers, null);
271 | }
272 |
273 | /**
274 | * Emits a type declaration.
275 | *
276 | * @param kind such as "class", "interface" or "enum".
277 | * @param extendsType the class to extend, or null for no extends clause.
278 | */
279 | public JavaWriter beginType(String type, String kind, Set modifiers, String extendsType,
280 | String... implementsTypes) throws IOException {
281 | indent();
282 | emitModifiers(modifiers);
283 | out.write(kind);
284 | out.write(" ");
285 | emitCompressedType(type);
286 | if (extendsType != null) {
287 | out.write(" extends ");
288 | emitCompressedType(extendsType);
289 | }
290 | if (implementsTypes.length > 0) {
291 | out.write("\n");
292 | indent();
293 | out.write(" implements ");
294 | for (int i = 0; i < implementsTypes.length; i++) {
295 | if (i != 0) {
296 | out.write(", ");
297 | }
298 | emitCompressedType(implementsTypes[i]);
299 | }
300 | }
301 | out.write(" {\n");
302 | scopes.push("interface".equals(kind) ? Scope.INTERFACE_DECLARATION : Scope.TYPE_DECLARATION);
303 | types.push(type);
304 | return this;
305 | }
306 |
307 | /** Completes the current type declaration. */
308 | public JavaWriter endType() throws IOException {
309 | popScope(Scope.TYPE_DECLARATION, Scope.INTERFACE_DECLARATION);
310 | types.pop();
311 | indent();
312 | out.write("}\n");
313 | return this;
314 | }
315 |
316 | /** Emits a field declaration. */
317 | public JavaWriter emitField(String type, String name) throws IOException {
318 | return emitField(type, name, EnumSet.noneOf(Modifier.class), null);
319 | }
320 |
321 | /** Emits a field declaration. */
322 | public JavaWriter emitField(String type, String name, Set modifiers)
323 | throws IOException {
324 | return emitField(type, name, modifiers, null);
325 | }
326 |
327 | /** Emits a field declaration. */
328 | public JavaWriter emitField(String type, String name, Set modifiers,
329 | String initialValue) throws IOException {
330 | indent();
331 | emitModifiers(modifiers);
332 | emitCompressedType(type);
333 | out.write(" ");
334 | out.write(name);
335 |
336 | if (initialValue != null) {
337 | out.write(" =");
338 | if (!initialValue.startsWith("\n")) {
339 | out.write(" ");
340 | }
341 |
342 | String[] lines = initialValue.split("\n", -1);
343 | out.write(lines[0]);
344 | for (int i = 1; i < lines.length; i++) {
345 | out.write("\n");
346 | hangingIndent();
347 | out.write(lines[i]);
348 | }
349 | }
350 | out.write(";\n");
351 | return this;
352 | }
353 |
354 | /**
355 | * Emit a method declaration.
356 | *
357 | *
A {@code null} return type may be used to indicate a constructor, but
358 | * {@link #beginConstructor(Set, String...)} should be preferred. This behavior may be removed in
359 | * a future release.
360 | *
361 | * @param returnType the method's return type, or null for constructors
362 | * @param name the method name, or the fully qualified class name for constructors.
363 | * @param modifiers the set of modifiers to be applied to the method
364 | * @param parameters alternating parameter types and names.
365 | */
366 | public JavaWriter beginMethod(String returnType, String name, Set modifiers,
367 | String... parameters) throws IOException {
368 | return beginMethod(returnType, name, modifiers, Arrays.asList(parameters), null);
369 | }
370 |
371 | /**
372 | * Emit a method declaration.
373 | *
374 | *
A {@code null} return type may be used to indicate a constructor, but
375 | * {@link #beginConstructor(Set, List, List)} should be preferred. This behavior may be removed in
376 | * a future release.
377 | *
378 | * @param returnType the method's return type, or null for constructors.
379 | * @param name the method name, or the fully qualified class name for constructors.
380 | * @param modifiers the set of modifiers to be applied to the method
381 | * @param parameters alternating parameter types and names.
382 | * @param throwsTypes the classes to throw, or null for no throws clause.
383 | */
384 | public JavaWriter beginMethod(String returnType, String name, Set modifiers,
385 | List parameters, List throwsTypes) throws IOException {
386 | indent();
387 | emitModifiers(modifiers);
388 | if (returnType != null) {
389 | emitCompressedType(returnType);
390 | out.write(" ");
391 | out.write(name);
392 | } else {
393 | emitCompressedType(name);
394 | }
395 | out.write("(");
396 | if (parameters != null) {
397 | for (int p = 0; p < parameters.size();) {
398 | if (p != 0) {
399 | out.write(", ");
400 | }
401 | emitCompressedType(parameters.get(p++));
402 | out.write(" ");
403 | emitCompressedType(parameters.get(p++));
404 | }
405 | }
406 | out.write(")");
407 | if (throwsTypes != null && throwsTypes.size() > 0) {
408 | out.write("\n");
409 | indent();
410 | out.write(" throws ");
411 | for (int i = 0; i < throwsTypes.size(); i++) {
412 | if (i != 0) {
413 | out.write(", ");
414 | }
415 | emitCompressedType(throwsTypes.get(i));
416 | }
417 | }
418 | if (modifiers.contains(ABSTRACT) || Scope.INTERFACE_DECLARATION.equals(scopes.peek())) {
419 | out.write(";\n");
420 | scopes.push(Scope.ABSTRACT_METHOD);
421 | } else {
422 | out.write(" {\n");
423 | scopes.push(returnType == null ? Scope.CONSTRUCTOR : Scope.NON_ABSTRACT_METHOD);
424 | }
425 | return this;
426 | }
427 |
428 | public JavaWriter beginConstructor(Set modifiers, String... parameters)
429 | throws IOException {
430 | beginMethod(null, rawType(types.peekFirst()), modifiers, parameters);
431 | return this;
432 | }
433 |
434 | public JavaWriter beginConstructor(Set modifiers,
435 | List parameters, List throwsTypes)
436 | throws IOException {
437 | beginMethod(null, rawType(types.peekFirst()), modifiers, parameters, throwsTypes);
438 | return this;
439 | }
440 |
441 | /** Emits some Javadoc comments with line separated by {@code \n}. */
442 | public JavaWriter emitJavadoc(String javadoc, Object... params) throws IOException {
443 | String formatted = String.format(javadoc, params);
444 |
445 | indent();
446 | out.write("/**\n");
447 | for (String line : formatted.split("\n")) {
448 | indent();
449 | out.write(" *");
450 | if (!line.isEmpty()) {
451 | out.write(" ");
452 | out.write(line);
453 | }
454 | out.write("\n");
455 | }
456 | indent();
457 | out.write(" */\n");
458 | return this;
459 | }
460 |
461 | /** Emits a single line comment. */
462 | public JavaWriter emitSingleLineComment(String comment, Object... args) throws IOException {
463 | indent();
464 | out.write("// ");
465 | out.write(String.format(comment, args));
466 | out.write("\n");
467 | return this;
468 | }
469 |
470 | public JavaWriter emitEmptyLine() throws IOException {
471 | out.write("\n");
472 | return this;
473 | }
474 |
475 | public JavaWriter emitEnumValue(String name) throws IOException {
476 | indent();
477 | out.write(name);
478 | out.write(",\n");
479 | return this;
480 | }
481 |
482 | /**
483 | * A simple switch to emit the proper enum depending if its last causing it to be terminated
484 | * by a semi-colon ({@code ;}).
485 | */
486 | public JavaWriter emitEnumValue(String name, boolean isLast) throws IOException {
487 | return isLast ? emitLastEnumValue(name) : emitEnumValue(name);
488 | }
489 |
490 | private JavaWriter emitLastEnumValue(String name) throws IOException {
491 | indent();
492 | out.write(name);
493 | out.write(";\n");
494 | return this;
495 | }
496 |
497 | /** Emit a list of enum values followed by a semi-colon ({@code ;}). */
498 | public JavaWriter emitEnumValues(Iterable names) throws IOException {
499 | Iterator iterator = names.iterator();
500 |
501 | while (iterator.hasNext()) {
502 | String name = iterator.next();
503 | if (iterator.hasNext()) {
504 | emitEnumValue(name);
505 | } else {
506 | emitLastEnumValue(name);
507 | }
508 | }
509 |
510 | return this;
511 | }
512 |
513 | /** Equivalent to {@code annotation(annotation, emptyMap())}. */
514 | public JavaWriter emitAnnotation(String annotation) throws IOException {
515 | return emitAnnotation(annotation, Collections.emptyMap());
516 | }
517 |
518 | /** Equivalent to {@code annotation(annotationType.getName(), emptyMap())}. */
519 | public JavaWriter emitAnnotation(Class extends Annotation> annotationType) throws IOException {
520 | return emitAnnotation(type(annotationType), Collections.emptyMap());
521 | }
522 |
523 | /**
524 | * Annotates the next element with {@code annotationType} and a {@code value}.
525 | *
526 | * @param value an object used as the default (value) parameter of the annotation. The value will
527 | * be encoded using Object.toString(); use {@link #stringLiteral} for String values. Object
528 | * arrays are written one element per line.
529 | */
530 | public JavaWriter emitAnnotation(Class extends Annotation> annotationType, Object value)
531 | throws IOException {
532 | return emitAnnotation(type(annotationType), value);
533 | }
534 |
535 | /**
536 | * Annotates the next element with {@code annotation} and a {@code value}.
537 | *
538 | * @param value an object used as the default (value) parameter of the annotation. The value will
539 | * be encoded using Object.toString(); use {@link #stringLiteral} for String values. Object
540 | * arrays are written one element per line.
541 | */
542 | public JavaWriter emitAnnotation(String annotation, Object value) throws IOException {
543 | indent();
544 | out.write("@");
545 | emitCompressedType(annotation);
546 | out.write("(");
547 | emitAnnotationValue(value);
548 | out.write(")");
549 | out.write("\n");
550 | return this;
551 | }
552 |
553 | /** Equivalent to {@code annotation(annotationType.getName(), attributes)}. */
554 | public JavaWriter emitAnnotation(Class extends Annotation> annotationType,
555 | Map attributes) throws IOException {
556 | return emitAnnotation(type(annotationType), attributes);
557 | }
558 |
559 | /**
560 | * Annotates the next element with {@code annotation} and {@code attributes}.
561 | *
562 | * @param attributes a map from annotation attribute names to their values. Values are encoded
563 | * using Object.toString(); use {@link #stringLiteral} for String values. Object arrays are
564 | * written one element per line.
565 | */
566 | public JavaWriter emitAnnotation(String annotation, Map attributes)
567 | throws IOException {
568 | indent();
569 | out.write("@");
570 | emitCompressedType(annotation);
571 | switch (attributes.size()) {
572 | case 0:
573 | break;
574 | case 1:
575 | Entry onlyEntry = attributes.entrySet().iterator().next();
576 | out.write("(");
577 | if (!"value".equals(onlyEntry.getKey())) {
578 | out.write(onlyEntry.getKey());
579 | out.write(" = ");
580 | }
581 | emitAnnotationValue(onlyEntry.getValue());
582 | out.write(")");
583 | break;
584 | default:
585 | boolean split = attributes.size() > MAX_SINGLE_LINE_ATTRIBUTES
586 | || containsArray(attributes.values());
587 | out.write("(");
588 | scopes.push(Scope.ANNOTATION_ATTRIBUTE);
589 | String separator = split ? "\n" : "";
590 | for (Entry entry : attributes.entrySet()) {
591 | out.write(separator);
592 | separator = split ? ",\n" : ", ";
593 | if (split) {
594 | indent();
595 | }
596 | out.write(entry.getKey());
597 | out.write(" = ");
598 | Object value = entry.getValue();
599 | emitAnnotationValue(value);
600 | }
601 | popScope(Scope.ANNOTATION_ATTRIBUTE);
602 | if (split) {
603 | out.write("\n");
604 | indent();
605 | }
606 | out.write(")");
607 | break;
608 | }
609 | out.write("\n");
610 | return this;
611 | }
612 |
613 | private boolean containsArray(Collection> values) {
614 | for (Object value : values) {
615 | if (value instanceof Object[]) {
616 | return true;
617 | }
618 | }
619 | return false;
620 | }
621 |
622 | /**
623 | * Writes a single annotation value. If the value is an array, each element in the array will be
624 | * written to its own line.
625 | */
626 | private JavaWriter emitAnnotationValue(Object value) throws IOException {
627 | if (value instanceof Object[]) {
628 | out.write("{");
629 | boolean firstValue = true;
630 | scopes.push(Scope.ANNOTATION_ARRAY_VALUE);
631 | for (Object o : ((Object[]) value)) {
632 | if (firstValue) {
633 | firstValue = false;
634 | out.write("\n");
635 | } else {
636 | out.write(",\n");
637 | }
638 | indent();
639 | out.write(o.toString());
640 | }
641 | popScope(Scope.ANNOTATION_ARRAY_VALUE);
642 | out.write("\n");
643 | indent();
644 | out.write("}");
645 | } else {
646 | out.write(value.toString());
647 | }
648 | return this;
649 | }
650 |
651 | /**
652 | * @param pattern a code pattern like "int i = %s". Newlines will be further indented. Should not
653 | * contain trailing semicolon.
654 | */
655 | public JavaWriter emitStatement(String pattern, Object... args) throws IOException {
656 | checkInMethod();
657 | String[] lines = String.format(pattern, args).split("\n", -1);
658 | indent();
659 | out.write(lines[0]);
660 | for (int i = 1; i < lines.length; i++) {
661 | out.write("\n");
662 | hangingIndent();
663 | out.write(lines[i]);
664 | }
665 | out.write(";\n");
666 | return this;
667 | }
668 |
669 | /**
670 | * @param controlFlow the control flow construct and its code, such as "if (foo == 5)". Shouldn't
671 | * contain braces or newline characters.
672 | */
673 | public JavaWriter beginControlFlow(String controlFlow, Object... args) throws IOException {
674 | checkInMethod();
675 | indent();
676 | out.write(String.format(controlFlow, args));
677 | out.write(" {\n");
678 | scopes.push(Scope.CONTROL_FLOW);
679 | return this;
680 | }
681 |
682 | /**
683 | * @param controlFlow the control flow construct and its code, such as "else if (foo == 10)".
684 | * Shouldn't contain braces or newline characters.
685 | */
686 | public JavaWriter nextControlFlow(String controlFlow, Object... args) throws IOException {
687 | popScope(Scope.CONTROL_FLOW);
688 | indent();
689 | scopes.push(Scope.CONTROL_FLOW);
690 | out.write("} ");
691 | out.write(String.format(controlFlow, args));
692 | out.write(" {\n");
693 | return this;
694 | }
695 |
696 | public JavaWriter endControlFlow() throws IOException {
697 | return endControlFlow(null);
698 | }
699 |
700 | /**
701 | * @param controlFlow the optional control flow construct and its code, such as
702 | * "while(foo == 20)". Only used for "do/while" control flows.
703 | */
704 | public JavaWriter endControlFlow(String controlFlow, Object... args) throws IOException {
705 | popScope(Scope.CONTROL_FLOW);
706 | indent();
707 | if (controlFlow != null) {
708 | out.write("} ");
709 | out.write(String.format(controlFlow, args));
710 | out.write(";\n");
711 | } else {
712 | out.write("}\n");
713 | }
714 | return this;
715 | }
716 |
717 | /** Completes the current method declaration. */
718 | public JavaWriter endMethod() throws IOException {
719 | Scope popped = scopes.pop();
720 | // support calling a constructor a "method" to support the legacy code
721 | if (popped == Scope.NON_ABSTRACT_METHOD || popped == Scope.CONSTRUCTOR) {
722 | indent();
723 | out.write("}\n");
724 | } else if (popped != Scope.ABSTRACT_METHOD) {
725 | throw new IllegalStateException();
726 | }
727 | return this;
728 | }
729 |
730 | /** Completes the current constructor declaration. */
731 | public JavaWriter endConstructor() throws IOException {
732 | popScope(Scope.CONSTRUCTOR);
733 | indent();
734 | out.write("}\n");
735 | return this;
736 | }
737 |
738 | /** Returns the string literal representing {@code data}, including wrapping quotes. */
739 | public static String stringLiteral(String data) {
740 | StringBuilder result = new StringBuilder();
741 | result.append('"');
742 | for (int i = 0; i < data.length(); i++) {
743 | char c = data.charAt(i);
744 | switch (c) {
745 | case '"':
746 | result.append("\\\"");
747 | break;
748 | case '\\':
749 | result.append("\\\\");
750 | break;
751 | case '\b':
752 | result.append("\\b");
753 | break;
754 | case '\t':
755 | result.append("\\t");
756 | break;
757 | case '\n':
758 | result.append("\\n");
759 | break;
760 | case '\f':
761 | result.append("\\f");
762 | break;
763 | case '\r':
764 | result.append("\\r");
765 | break;
766 | default:
767 | if (Character.isISOControl(c)) {
768 | result.append(String.format("\\u%04x", (int) c));
769 | } else {
770 | result.append(c);
771 | }
772 | }
773 | }
774 | result.append('"');
775 | return result.toString();
776 | }
777 |
778 | /** Build a string representation of a type and optionally its generic type arguments. */
779 | public static String type(Class> raw, String... parameters) {
780 | if (parameters.length == 0) {
781 | return raw.getCanonicalName();
782 | }
783 | if (raw.getTypeParameters().length != parameters.length) {
784 | throw new IllegalArgumentException();
785 | }
786 | StringBuilder result = new StringBuilder();
787 | result.append(raw.getCanonicalName());
788 | result.append("<");
789 | result.append(parameters[0]);
790 | for (int i = 1; i < parameters.length; i++) {
791 | result.append(", ");
792 | result.append(parameters[i]);
793 | }
794 | result.append(">");
795 | return result.toString();
796 | }
797 |
798 | /** Build a string representation of the raw type for a (optionally generic) type. */
799 | public static String rawType(String type) {
800 | int lessThanIndex = type.indexOf('<');
801 | if (lessThanIndex != -1) {
802 | return type.substring(0, lessThanIndex);
803 | }
804 | return type;
805 | }
806 |
807 | @Override public void close() throws IOException {
808 | out.close();
809 | }
810 |
811 | /** Emits the modifiers to the writer. */
812 | private void emitModifiers(Set modifiers) throws IOException {
813 | if (modifiers.isEmpty()) {
814 | return;
815 | }
816 | // Use an EnumSet to ensure the proper ordering
817 | if (!(modifiers instanceof EnumSet)) {
818 | modifiers = EnumSet.copyOf(modifiers);
819 | }
820 | for (Modifier modifier : modifiers) {
821 | out.append(modifier.toString()).append(' ');
822 | }
823 | }
824 |
825 | private void indent() throws IOException {
826 | for (int i = 0, count = scopes.size(); i < count; i++) {
827 | out.write(indent);
828 | }
829 | }
830 |
831 | private void hangingIndent() throws IOException {
832 | for (int i = 0, count = scopes.size() + 2; i < count; i++) {
833 | out.write(indent);
834 | }
835 | }
836 |
837 | private static final EnumSet
838 | METHOD_SCOPES = EnumSet.of(Scope.NON_ABSTRACT_METHOD, Scope.CONSTRUCTOR, Scope.CONTROL_FLOW,
839 | Scope.INITIALIZER);
840 |
841 | private void checkInMethod() {
842 | if (!METHOD_SCOPES.contains(scopes.peekFirst())) {
843 | throw new IllegalArgumentException();
844 | }
845 | }
846 |
847 | private void popScope(Scope... expected) {
848 | if (!EnumSet.copyOf(Arrays.asList(expected)).contains(scopes.pop())) {
849 | throw new IllegalStateException();
850 | }
851 | }
852 |
853 | private enum Scope {
854 | TYPE_DECLARATION,
855 | INTERFACE_DECLARATION,
856 | ABSTRACT_METHOD,
857 | NON_ABSTRACT_METHOD,
858 | CONSTRUCTOR,
859 | CONTROL_FLOW,
860 | ANNOTATION_ATTRIBUTE,
861 | ANNOTATION_ARRAY_VALUE,
862 | INITIALIZER
863 | }
864 | }
865 |
--------------------------------------------------------------------------------
/processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor:
--------------------------------------------------------------------------------
1 | com.hannesdorfmann.parcelableplease.processor.ParcelablePleaseProcessor
--------------------------------------------------------------------------------
/processor/src/test/java/com/hannesdorfmann/parcelableplease/processor/ParcelablePleaseProcessorTest.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.processor;
2 |
3 | import com.google.common.truth.Truth;
4 | import com.google.testing.compile.JavaFileObjects;
5 | import com.google.testing.compile.JavaSourceSubjectFactory;
6 | import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
7 | import javax.tools.JavaFileObject;
8 | import org.junit.Test;
9 |
10 | /**
11 | * @author Hannes Dorfmann
12 | */
13 | public class ParcelablePleaseProcessorTest {
14 |
15 | @Test
16 | public void abstractClass() {
17 |
18 | String annotation = ParcelablePlease.class.getCanonicalName();
19 | JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.AbstractClass",
20 | "package test;",
21 | "",
22 | "@" + annotation,
23 | "abstract class AbstractClass {}");
24 |
25 | Truth.assertAbout(JavaSourceSubjectFactory.javaSource())
26 | .that(componentFile).processedWith(new ParcelablePleaseProcessor())
27 | .failsToCompile()
28 | .withErrorContaining("Element AbstractClass is annotated with @ParcelablePlease but is an abstract class. Abstract classes can not be annotated. Annotate the concrete class that implements all abstract methods with @ParcelablePlease");
29 |
30 | }
31 |
32 | @Test
33 | public void simpleClass() {
34 |
35 | String annotation = ParcelablePlease.class.getCanonicalName();
36 | JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.SimpleClass",
37 | "package test;",
38 | "",
39 | "@" + annotation,
40 | "class SimpleClass {" +
41 | "int id;" +
42 | "String name;" +
43 | "}");
44 |
45 | Truth.assertAbout(JavaSourceSubjectFactory.javaSource())
46 | .that(componentFile).processedWith(new ParcelablePleaseProcessor())
47 | .compilesWithoutError();
48 | }
49 |
50 |
51 | @Test
52 | public void innerClass() {
53 |
54 | String annotation = ParcelablePlease.class.getCanonicalName();
55 | JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.OuterClass",
56 | "package test;",
57 | "",
58 | "class OuterClass {",
59 | "@" + annotation,
60 | "class InnerClass {",
61 | "int id;",
62 | "String name;" ,
63 | "}",
64 | "}");
65 |
66 | Truth.assertAbout(JavaSourceSubjectFactory.javaSource())
67 | .that(componentFile).processedWith(new ParcelablePleaseProcessor())
68 | .compilesWithoutError();
69 | }
70 |
71 | @Test
72 | public void stringList() {
73 |
74 | String annotation = ParcelablePlease.class.getCanonicalName();
75 | JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.StringListTest",
76 | "package test;",
77 | "",
78 | "@" + annotation,
79 | "class StringListTest {",
80 | " java.util.List strings;",
81 | "}");
82 |
83 | Truth.assertAbout(JavaSourceSubjectFactory.javaSource())
84 | .that(componentFile).processedWith(new ParcelablePleaseProcessor())
85 | .compilesWithoutError();
86 | }
87 |
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 |
--------------------------------------------------------------------------------
/sample/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.neenbedankt.android-apt'
3 |
4 | android {
5 | compileSdkVersion 21
6 | buildToolsVersion "21.1.2"
7 |
8 | defaultConfig {
9 | applicationId "com.hannesdorfmann.parcelableplease.sample"
10 | minSdkVersion 8
11 | targetSdkVersion 21
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | def version = '1.0.2-SNAPSHOT'
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | compile 'com.android.support:appcompat-v7:21.0.3'
28 |
29 | apt 'com.hannesdorfmann.parcelableplease:processor:' + version
30 | compile 'com.hannesdorfmann.parcelableplease:annotation:' + version
31 | compile 'com.jakewharton:butterknife:6.0.0'
32 | }
33 |
--------------------------------------------------------------------------------
/sample/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/hannes/android-sdks/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/sample/app/src/main/java/com/hannesdorfmann/parcelableplease/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.ActionBarActivity;
5 | import android.view.Menu;
6 | import android.view.MenuItem;
7 | import android.widget.TextView;
8 | import butterknife.ButterKnife;
9 | import butterknife.InjectView;
10 | import butterknife.OnClick;
11 | import com.hannesdorfmann.parcelableplease.sample.model.Banana;
12 | import com.hannesdorfmann.parcelableplease.sample.model.Fruit;
13 | import com.hannesdorfmann.parcelableplease.sample.model.Orange;
14 | import java.util.ArrayList;
15 |
16 | public class MainActivity extends ActionBarActivity {
17 |
18 | private final String KEY_FRUIT = "fruit";
19 |
20 | @InjectView(R.id.selectedFruit) TextView selectedFruitTextView;
21 |
22 | Fruit selectedFruit;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_main);
28 | ButterKnife.inject(this);
29 |
30 | if (savedInstanceState != null){
31 | selectedFruit = savedInstanceState.getParcelable(KEY_FRUIT);
32 | }
33 |
34 | updateUi();
35 | }
36 |
37 | @Override protected void onSaveInstanceState(Bundle outState) {
38 | super.onSaveInstanceState(outState);
39 | outState.putParcelable(KEY_FRUIT, selectedFruit);
40 | }
41 |
42 | @Override
43 | public boolean onCreateOptionsMenu(Menu menu) {
44 | // Inflate the menu; this adds items to the action bar if it is present.
45 | getMenuInflater().inflate(R.menu.menu_main, menu);
46 | return true;
47 | }
48 |
49 | @Override
50 | public boolean onOptionsItemSelected(MenuItem item) {
51 | // Handle action bar item clicks here. The action bar will
52 | // automatically handle clicks on the Home/Up button, so long
53 | // as you specify a parent activity in AndroidManifest.xml.
54 | int id = item.getItemId();
55 |
56 | //noinspection SimplifiableIfStatement
57 | if (id == R.id.action_settings) {
58 | return true;
59 | }
60 |
61 | return super.onOptionsItemSelected(item);
62 | }
63 |
64 | @OnClick(R.id.banana)
65 | public void onBananaClicked() {
66 | selectedFruit = new Banana();
67 | updateUi();
68 | }
69 |
70 | @OnClick(R.id.orange)
71 | public void onOrangeClicked() {
72 | Orange orange = new Orange();
73 | orange.content = new ArrayList<>();
74 | orange.content.add("First");
75 | orange.content.add("Second");
76 | selectedFruit = orange;
77 | updateUi();
78 | }
79 |
80 | private void updateUi() {
81 | String fruit = "";
82 | if (selectedFruit != null) {
83 | fruit = selectedFruit.toString();
84 | }
85 | selectedFruitTextView.setText(fruit);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/sample/app/src/main/java/com/hannesdorfmann/parcelableplease/sample/model/Banana.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.sample.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 | import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
6 |
7 | /**
8 | * @author Hannes Dorfmann
9 | */
10 | @ParcelablePlease public class Banana extends Fruit implements Parcelable {
11 |
12 | public Banana() {
13 | super("Banana", FruitType.B);
14 | }
15 |
16 |
17 | @Override public int describeContents() {
18 | return 0;
19 | }
20 |
21 | @Override public void writeToParcel(Parcel dest, int flags) {
22 | BananaParcelablePlease.writeToParcel(this, dest, flags);
23 | }
24 |
25 | public static final Creator CREATOR = new Creator() {
26 | public Banana createFromParcel(Parcel source) {
27 | Banana target = new Banana();
28 | BananaParcelablePlease.readFromParcel(target, source);
29 | return target;
30 | }
31 |
32 | public Banana[] newArray(int size) {
33 | return new Banana[size];
34 | }
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/sample/app/src/main/java/com/hannesdorfmann/parcelableplease/sample/model/Fruit.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.sample.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 | import com.hannesdorfmann.parcelableplease.annotation.Bagger;
6 | import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
7 |
8 | /**
9 | * @author Hannes Dorfmann
10 | */
11 | @ParcelablePlease public class Fruit implements Parcelable {
12 |
13 | String name;
14 |
15 | @Bagger(FruitTypeBagger.class) FruitType type;
16 |
17 | public Fruit(String name, FruitType type) {
18 | this.name = name;
19 | this.type = type;
20 | }
21 |
22 | protected Fruit() {
23 |
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public FruitType getType() {
31 | return type;
32 | }
33 |
34 | @Override public String toString() {
35 | return name + "(" + type + ")";
36 | }
37 |
38 | @Override public int describeContents() {
39 | return 0;
40 | }
41 |
42 | @Override public void writeToParcel(Parcel dest, int flags) {
43 | FruitParcelablePlease.writeToParcel(this, dest, flags);
44 | }
45 |
46 | public static final Creator CREATOR = new Creator() {
47 | public Fruit createFromParcel(Parcel source) {
48 | Fruit target = new Fruit();
49 | FruitParcelablePlease.readFromParcel(target, source);
50 | return target;
51 | }
52 |
53 | public Fruit[] newArray(int size) {
54 | return new Fruit[size];
55 | }
56 | };
57 | }
58 |
--------------------------------------------------------------------------------
/sample/app/src/main/java/com/hannesdorfmann/parcelableplease/sample/model/FruitType.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.sample.model;
2 |
3 | /**
4 | * @author Hannes Dorfmann
5 | */
6 | public enum FruitType {
7 |
8 | A,
9 | B,
10 | C
11 |
12 | }
13 |
14 |
15 |
--------------------------------------------------------------------------------
/sample/app/src/main/java/com/hannesdorfmann/parcelableplease/sample/model/FruitTypeBagger.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.sample.model;
2 |
3 | import android.os.Parcel;
4 | import com.hannesdorfmann.parcelableplease.ParcelBagger;
5 |
6 | /**
7 | * @author Hannes Dorfmann
8 | */
9 | public class FruitTypeBagger implements ParcelBagger {
10 |
11 | @Override public void write(FruitType value, Parcel out, int flags) {
12 | out.writeString(value.toString());
13 | }
14 |
15 | @Override public FruitType read(Parcel in) {
16 | return FruitType.valueOf(in.readString());
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/sample/app/src/main/java/com/hannesdorfmann/parcelableplease/sample/model/Orange.java:
--------------------------------------------------------------------------------
1 | package com.hannesdorfmann.parcelableplease.sample.model;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 | import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
6 | import java.util.List;
7 |
8 | /**
9 | * @author Hannes Dorfmann
10 | */
11 | @ParcelablePlease public class Orange extends Fruit implements Parcelable {
12 |
13 | public Orange() {
14 | super("Orange", FruitType.C);
15 | }
16 |
17 | public List content;
18 |
19 | @Override public int describeContents() {
20 | return 0;
21 | }
22 |
23 | @Override public void writeToParcel(Parcel dest, int flags) {
24 | OrangeParcelablePlease.writeToParcel(this, dest, flags);
25 | }
26 |
27 | public static final Creator CREATOR = new Creator() {
28 | public Orange createFromParcel(Parcel source) {
29 | Orange target = new Orange();
30 | OrangeParcelablePlease.readFromParcel(target, source);
31 | return target;
32 | }
33 |
34 | public Orange[] newArray(int size) {
35 | return new Orange[size];
36 | }
37 | };
38 |
39 | @Override public String toString() {
40 | return super.toString() + " "+content;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/sample/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/sample/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/sample/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/sample/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/sample/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
20 |
21 |
22 |
30 |
31 |
32 |
40 |
41 |
42 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/sample/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/sample/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/sample/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | sample
5 | Select a fruit by clicking on the button below:
6 | Settings
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.0.0'
9 |
10 |
11 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | jcenter()
21 | maven { url "${System.env.HOME}/.m2/repository" }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/sample/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sockeqwe/ParcelablePlease/4bcb6695ade8cb0ec60af5b137b60f751262086c/sample/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/sample/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/sample/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/sample/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------