├── .gitignore
├── .travis.yml
├── README.md
├── annotation
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── com
│ └── lzh
│ └── compiler
│ └── parceler
│ └── annotation
│ ├── Arg.java
│ ├── BundleBuilder.java
│ ├── BundleConverter.java
│ ├── Converter.java
│ ├── FastJsonConverter.java
│ ├── GsonConverter.java
│ └── NonNull.java
├── api
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── lzh
│ └── compiler
│ └── parceler
│ ├── ActivityResultCallback.java
│ ├── ActivityResultDispatcher.java
│ ├── BundleFactory.java
│ ├── BundleHandle.java
│ ├── CacheManager.java
│ ├── Constants.java
│ ├── IBundleBuilder.java
│ ├── IntentLauncher.java
│ ├── ParcelInjector.java
│ ├── Parceler.java
│ ├── RuntimeInjector.java
│ └── Utils.java
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── lzh
│ │ └── compiler
│ │ └── parcelerdemo
│ │ ├── BundleActivity.java
│ │ ├── InjectorActivity.java
│ │ ├── KotlinLoginActivity.kt
│ │ ├── LoginActivity.java
│ │ ├── MainActivity.java
│ │ ├── TestCastActivity.java
│ │ ├── base
│ │ └── BaseActivity.java
│ │ └── bean
│ │ ├── Book.java
│ │ ├── BundleInfo.java
│ │ ├── Info.java
│ │ ├── NormalUser.java
│ │ └── SerialUser.java
│ └── res
│ ├── layout
│ ├── activity_bundle.xml
│ ├── activity_injector.xml
│ ├── activity_login.xml
│ ├── activity_main.xml
│ └── activity_test_cast.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── compiler
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── lzh
│ │ └── compiler
│ │ └── parceler
│ │ └── processor
│ │ ├── ParcelException.java
│ │ ├── ParcelerCompiler.java
│ │ ├── factory
│ │ ├── BuilderFactory.java
│ │ └── ClassFactory.java
│ │ ├── model
│ │ ├── Constants.java
│ │ ├── ElementParser.java
│ │ └── FieldData.java
│ │ └── util
│ │ ├── UtilMgr.java
│ │ └── Utils.java
│ └── resources
│ └── META-INF
│ └── services
│ └── javax.annotation.processing.Processor
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── javadoc.gradle
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 |
10 | .idea/
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: android
2 | jdk: oraclejdk8
3 | sudo: false
4 |
5 | android:
6 | components:
7 | - platform-tools
8 | - tools
9 | - build-tools-25.0.0
10 | - android-23
11 | - sys-img-armeabi-v7a-android-23
12 | - extra-android-m2repository
13 | licenses:
14 | - 'android-sdk-preview-license-52d11cd2'
15 | - 'android-sdk-license-.+'
16 | - 'google-gdk-license-.+'
17 |
18 | script: ./gradlew clean assemble --stacktrace
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Parceler
2 |
3 | Parceler是一款简单、轻量级的Bundle数据存取扩展框架。
4 |
5 | 使用此框架,你可以做到:
6 |
7 | 1. 向Bundle中存入任意类型的数据
8 | 2. 从Bundle中读取任意类型的数据
9 | 3. 将数据从Bundle容易中注入到指定的成员变量中去
10 | 4. 将数据从指定成员变量中注入到Bundle中去
11 | 5. 更方便的进行页面启动传值(避免key值硬编码)
12 | 6. 支持在kotlin环境下使用
13 | 7. 实现onActivityResult回调派发。避免到onActivityResult中做一堆判断。
14 |
15 | 更重要的:框架的**总方法数不到100,且无任何额外依赖**!
16 |
17 | ## 依赖
18 |
19 | > 添加JitPack仓库
20 |
21 | ```Groovy
22 | maven { url 'https://jitpack.io' }
23 | ```
24 |
25 | > 添加依赖
26 |
27 | LastestVersion=[](https://jitpack.io/#yjfnypeu/Parceler)
28 |
29 | ```Groovy
30 | dependencies {
31 | // 若要在kotlin环境下使用,请将annotationProcessor替换为kapt。
32 | annotationProcessor "com.github.yjfnypeu.Parceler:compiler:$LastestVersion"
33 | implementation "com.github.yjfnypeu.Parceler:api:$LastestVersion"
34 | }
35 | ```
36 |
37 | ## 用法
38 |
39 | ### 1. 配置数据转换器
40 |
41 | 数据转换器是框架的核心类,只有配置过对应的数据转换器才能使框架做到**支持对任意类型数据进行存取**的效果。
42 |
43 | 由于常用的数据格式是JSON。所以框架针对流行的fastjson与GSON分别定制了各自的转换器(**FastJsonConverter**和**GsonConverter**),方便进行直接使用。
44 |
45 | 请注意,框架本身并没有直接依赖fastjson或者GSON, 所以具体使用哪种转换器。取决于你当前的运行环境支持使用哪种转换器,比如我们项目有依赖fastjson。那么就可以选择依赖FastJson的转换器:
46 |
47 | ```
48 | Parceler.setDefaultConverter(FastJsonConverter.class);
49 | ```
50 |
51 | 啰嗦了那么多,其实就是一句配置即可,然后就可以直接进行方便的数据存取了。
52 |
53 | ### 2. 使用BundleFactory进行任意数据存取
54 |
55 | 框架提供BundleFactory类来作为数据存取的操作类:
56 |
57 | ```
58 | // 创建操作类实例。bundle为所需要的Bundle数据容器。
59 | // 若为null则将创建一个新的Bundle对应提供使用
60 | BundleFactory factory = Parceler.createFactory(bundle);
61 |
62 | // 通过factory对象进行数据存取
63 | ...
64 |
65 | // 操作完成后。获取操作完成后的Bundle容器实例
66 | Bundle result = factory.getBundle();
67 | ```
68 |
69 | 然后即可使用此BundleFactory对任意数据进行存取:
70 |
71 | ```java
72 | // 将指定数据value使用key值存入bundle中
73 | factory.put(key, value);
74 | // 将指定key值的数据从bundle中取出,并转换为指定type数据类型再返回
75 | T t = factory.get(key, Class);
76 | ```
77 |
78 | #### 示例说明
79 |
80 | 当前我们有两个不同的实体类:
81 |
82 | ```java
83 | // NormalUser未实现序列化
84 | public class NormalUser {
85 | public String username;
86 | }
87 | // SerialUser实现序列化
88 | public class SerialUser implements Serializable {
89 | public String username;
90 | }
91 | ```
92 |
93 | 然后进行数据存储:
94 |
95 | ```
96 | NormalUser normalUser = new NormalUser();
97 | SerialUser serialUser = new SerialUser();
98 | normalUser.username = "this is normal user bean";
99 | serialUser.username = "this is serial user bean";
100 |
101 | BundleFactory factory = Parceler.createFactory(new Bundle());
102 | factory.put("normal", normalUser);
103 | factory.put("serial", serialUser);
104 |
105 | Bundle result = factory.getBundle();
106 | ```
107 |
108 | 最终result数据:
109 |
110 | 
111 |
112 | 可以看到:NormalUser的实例被自动转换成了JSON进行存储了。
113 |
114 | 然后再从Bundle中进行数据读取:
115 |
116 | ```
117 | NormalUser newNormalUser = factory.get("normal", NormalUser.class);
118 | SerialUser newSerialUser = factory.get("serial", SerialUser.class);
119 | ```
120 |
121 | 
122 |
123 | ### 3. Bundle数据自动注入
124 |
125 | 最常见的使用场景就是在进行Activity跳转传值时使用:
126 |
127 | 发起注入操作可放置于基类中进行使用。所以可以将注入操作添加在Activity基类中:
128 |
129 | ```java
130 | // 将注入器配置到基类中。一次配置,所有子类共同使用
131 | public abstract class BaseActivity extends Activity {
132 |
133 | @Override
134 | protected void onCreate(Bundle savedInstanceState) {
135 | super.onCreate(savedInstanceState);
136 | // 启动时从intent中读取数据并注入到当前类中。
137 | Parceler.toEntity(this,getIntent());
138 | }
139 |
140 | // ============可用以下方式方便的进行数据现场保护==========
141 | @Override
142 | protected void onSaveInstanceState(Bundle outState) {
143 | super.onSaveInstanceState(outState);
144 | // 将当前类中的使用注解的成员变量的值注入到outState中进行保存。
145 | Parceler.toBundle(this,outState);
146 | }
147 |
148 | @Override
149 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
150 | super.onRestoreInstanceState(savedInstanceState);
151 | // 需要恢复现场时。将数据从saveInstanceState中读取并注入当前类中。恢复现场
152 | Parceler.toEntity(this,savedInstanceState);
153 | }
154 | }
155 | ```
156 |
157 | 然后就可以愉快的在各种子类中方便的进行使用了:
158 |
159 | ```java
160 | public class UserActivity extends BaseActivity {
161 |
162 | // 直接使用。
163 | @Arg
164 | User user;
165 | // 使用指定key值
166 | @Arg("rename_address")
167 | Address address;
168 | @Arg
169 | int age;
170 |
171 | ...
172 |
173 | }
174 | ```
175 |
176 | 然后当此UserActivity页面启动后,即可自动将getIntent中的bundle数据,注入到这些被Arg所注解的成员变量中去。
177 |
178 | ### 4. 使用BundleBuilder, 避免key值硬编码
179 |
180 | 以上方的UserActivity为例。需要跳转到此页面并将数据传递过去。我们需要将数据装入Intent中:
181 |
182 | 常见的使用流程都应该是下面这样的:
183 |
184 | ```
185 | Bundle bundle = Parceler.createFactory(null)
186 | .put("user", user)
187 | .put("address", address)
188 | .put("age", age)
189 | .getBundle();
190 |
191 | Intent intent = new Intent(this, UserActivity.class);
192 | intent.addExtras(bundle);
193 | startActivity(intent);
194 | ```
195 |
196 | 可以看到有很多的key值的硬编码。这在开发过程中其实是不推荐的。所以框架提供了BundleBuilder注解:
197 |
198 | ```java
199 | @BundleBuilder
200 | public class UserActivity extends BaseActivity {
201 | ...
202 | }
203 | ```
204 |
205 | 添加此注解后。将会生成对应的用于生成相应的bundle数据的类, 通过此生成类即可避免key值硬编码:
206 |
207 | ```java
208 | // 将数据通过生成类UserActivityBundleBuilder进行装载
209 | IBundleBuilder builder = UserActivityBundleBuilder.create(new Bundle())
210 | .setUser(user)
211 | .setAddress(address)
212 | .setAge(age);
213 |
214 | // 使用自带提供的IntentLauncher类,方便的进行启动
215 | Parceler.createLauncher(builder)
216 | .start(context);
217 |
218 | // 或者需要直接使用装载的数据
219 | Bundle result = builder.build();
220 | ```
221 |
222 | ### 5. 使用回调处理onActivityResult
223 |
224 | 使用此回调机制。需要在BaseActivity中配置回调的派发方法:
225 |
226 | ```
227 | public class BaseActivity extends Activity {
228 | @Override
229 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
230 | Parceler.dispatchActivityResult(this, requestCode, resultCode, data);
231 | }
232 | }
233 | ```
234 |
235 | 然后即可直接在启动时分别配置回调监听器:
236 |
237 | ```
238 | ActivityResultCallback callback = new ActivityResultCallback() {
239 | @Override
240 | public void onResult(int resultCode, Intent data) {
241 | // TODO
242 | }
243 | };
244 |
245 | Parceler.createLauncher(TargetActivity.class, bundle)
246 | .setResultCallback(callback)
247 | .start(activity);
248 | ```
249 |
250 | 友情提醒:当配置了有效的回调之后。可以选择不再设置requestCode。不用再每次都抓耳挠腮的去为requestCode取值了。
251 |
252 | ## 混淆配置
253 | ```Proguard
254 | -keep class com.lzh.compiler.parceler.annotation.**
255 | -keep class * implements com.lzh.compiler.parceler.ParcelInjector
256 | -keepclasseswithmembernames class * {
257 | @com.lzh.compiler.parceler.annotation.Arg ;
258 | }
259 | ```
260 |
261 | ## 联系作者
262 |
263 | 欢迎提issue
264 | Email:470368500@qq.com
265 | QQ Group:108895031
266 |
267 | ## License
268 | ```
269 | Copyright 2015 Haoge
270 |
271 | Licensed under the Apache License, Version 2.0 (the "License");
272 | you may not use this file except in compliance with the License.
273 | You may obtain a copy of the License at
274 |
275 | http://www.apache.org/licenses/LICENSE-2.0
276 |
277 | Unless required by applicable law or agreed to in writing, software
278 | distributed under the License is distributed on an "AS IS" BASIS,
279 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
280 | See the License for the specific language governing permissions and
281 | limitations under the License.
282 | ```
283 |
284 |
285 |
286 |
--------------------------------------------------------------------------------
/annotation/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/annotation/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'maven'
3 | dependencies {
4 | compileOnly 'com.alibaba:fastjson:1.2.31'
5 | compileOnly 'com.google.code.gson:gson:2.8.0'
6 | }
7 | targetCompatibility = '1.7'
8 | sourceCompatibility = '1.7'
9 |
10 | task sourcesJar(type: Jar, dependsOn: classes) {
11 | classifier = 'sources'
12 | from sourceSets.main.allSource
13 | }
14 |
15 | task javadocJar(type: Jar, dependsOn: javadoc) {
16 | classifier = 'javadoc'
17 | from javadoc.destinationDir
18 | }
19 |
20 | artifacts {
21 | archives sourcesJar
22 | archives javadocJar
23 | }
--------------------------------------------------------------------------------
/annotation/src/main/java/com/lzh/compiler/parceler/annotation/Arg.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler.annotation;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | /**
24 | * 此注解作用于任意实体类中的成员变量。用以标记此成员变量应该被数据注入器ParcelInjector读取并进行注入操作。
25 | *
26 | * @author haoge
27 | */
28 | @Target({ElementType.FIELD})
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface Arg {
31 | /**
32 | * 重命名key值。当为空时,表示将使用成员变量的名字作为从Bundle进行存取时所使用的key值。
33 | */
34 | String value() default "";
35 | }
36 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/lzh/compiler/parceler/annotation/BundleBuilder.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * Add this annotation to the class who need to generating Builder class.
10 | * @author haoge on 2017/12/25.
11 | */
12 | @Target({ElementType.TYPE})
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface BundleBuilder {
15 | }
16 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/lzh/compiler/parceler/annotation/BundleConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler.annotation;
17 |
18 | import java.lang.reflect.Type;
19 |
20 | /**
21 | * Bundle数据转换器。默认提供了两个json数据解析器:{@link FastJsonConverter}与{@link GsonConverter}.
22 | * @author haoge
23 | */
24 | public interface BundleConverter {
25 |
26 | /**
27 | * 将指定数据data转换为对应type的数据类型并返回。
28 | *
29 | *
30 | * 请注意:被转换后的数据。应与参数指定的转换数据类型type一致。
31 | *
32 | *
33 | * @return 转换后的数据
34 | */
35 | Object convertToEntity(Object data, Type type);
36 |
37 | /**
38 | * 将指定数据data。转换为可被放入Bundle中的数据类型。并返回。
39 | *
40 | *
41 | * 请注意:被转换后的数据类型。应该为可被直接放入Bundle类中的数据类型, 如json串
42 | *
43 | *
44 | * @return 被转换后的数据。
45 | */
46 | String convertToBundle(Object data);
47 | }
48 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/lzh/compiler/parceler/annotation/Converter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler.annotation;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | /**
24 | * 此注解作用于 已被{@link Arg}所标记 的成员变量之上。用于在生成注入器类中。对此成员变量进行的注入操作。使用此处指定的数据转换器。
25 | *
26 | * @author haoge
27 | */
28 | @Target({ElementType.FIELD})
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface Converter {
31 |
32 | Class extends BundleConverter> value();
33 | }
34 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/lzh/compiler/parceler/annotation/FastJsonConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler.annotation;
17 |
18 | import com.alibaba.fastjson.JSON;
19 | import com.lzh.compiler.parceler.annotation.BundleConverter;
20 |
21 | import java.lang.reflect.Type;
22 |
23 | /**
24 | * 默认提供的FastJson数据转换器。使用此转换器前。请确定你的项目依赖了fastjson。
25 | *
26 | * @author haoge
27 | */
28 | public final class FastJsonConverter implements BundleConverter {
29 |
30 | @Override
31 | public Object convertToEntity(Object data, Type type) {
32 | String json;
33 | if (data instanceof String) {
34 | json = (String) data;
35 | } else if (data instanceof StringBuilder || data instanceof StringBuffer) {
36 | json = data.toString();
37 | } else {
38 | throw new RuntimeException(String.format("Unsupported type %s to parse with fastjson", data.getClass()));
39 | }
40 |
41 | return JSON.parseObject(json, type);
42 | }
43 |
44 | @Override
45 | public String convertToBundle(Object data) {
46 | return JSON.toJSONString(data);
47 | }
48 |
49 | static {
50 | try {
51 | //noinspection unused
52 | String ignore = JSON.class.getCanonicalName();
53 | } catch (Throwable t) {
54 | throw new RuntimeException("You should add fastjson to your dependencies list first", t);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/lzh/compiler/parceler/annotation/GsonConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler.annotation;
17 |
18 | import com.google.gson.Gson;
19 | import com.lzh.compiler.parceler.annotation.BundleConverter;
20 |
21 | import java.lang.reflect.Type;
22 |
23 | /**
24 | * 默认提供的使用Gson的数据转换器,使用此转换器前。请确定你的项目依赖了gson。
25 | * @author haoge
26 | */
27 | public class GsonConverter implements BundleConverter{
28 | Gson gson = new Gson();
29 |
30 | @Override
31 | public Object convertToEntity(Object data, Type type) {
32 | String json;
33 | if (data instanceof String) {
34 | json = (String) data;
35 | } else if (data instanceof StringBuilder || data instanceof StringBuffer) {
36 | json = data.toString();
37 | } else {
38 | throw new RuntimeException(String.format("Unsupported type %s to parse with fastjson", data.getClass()));
39 | }
40 |
41 | return gson.fromJson(json, type);
42 | }
43 |
44 | @Override
45 | public String convertToBundle(Object data) {
46 | return gson.toJson(data);
47 | }
48 |
49 | static {
50 | try {
51 | //noinspection unused
52 | String ignore = Gson.class.getCanonicalName();
53 | } catch (Throwable t) {
54 | throw new RuntimeException("You should add Gson to your dependencies list first", t);
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/annotation/src/main/java/com/lzh/compiler/parceler/annotation/NonNull.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler.annotation;
17 |
18 | import java.lang.annotation.ElementType;
19 | import java.lang.annotation.Retention;
20 | import java.lang.annotation.RetentionPolicy;
21 | import java.lang.annotation.Target;
22 |
23 | /**
24 | * 此注解作用于已被{@link Arg}所标记的成员变量之上。用于在生成注入器类中。当未正确获取到对应的值时,强制抛出异常。
25 | *
26 | * @author haoge
27 | */
28 | @Target({ElementType.FIELD})
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface NonNull {
31 | }
32 |
--------------------------------------------------------------------------------
/api/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/api/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 |
4 | android {
5 | compileSdkVersion 21
6 | buildToolsVersion '27.0.3'
7 |
8 | defaultConfig {
9 | minSdkVersion 8
10 | targetSdkVersion 21
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | lintOptions {
22 | abortOnError false
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | api project(':annotation')
29 | }
30 |
31 | apply from: '../javadoc.gradle'
--------------------------------------------------------------------------------
/api/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/admin/Library/Android/sdk/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 |
--------------------------------------------------------------------------------
/api/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/ActivityResultCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import android.content.Intent;
19 |
20 | public interface ActivityResultCallback {
21 | void onResult(int resultCode, Intent data);
22 | }
23 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/ActivityResultDispatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.os.Build;
21 |
22 | import java.util.ArrayList;
23 | import java.util.HashMap;
24 | import java.util.Iterator;
25 | import java.util.List;
26 | import java.util.Map;
27 | import java.util.Set;
28 |
29 | final class ActivityResultDispatcher {
30 |
31 | private Map> container = new HashMap<>();
32 |
33 | private static ActivityResultDispatcher dispatcher = new ActivityResultDispatcher();
34 | private ActivityResultDispatcher(){ }
35 | public static ActivityResultDispatcher get() {
36 | return dispatcher;
37 | }
38 |
39 | void bindRequestArgs(Activity activity, int requestCode, ActivityResultCallback callback) {
40 | if (activity.isFinishing()
41 | || callback == null
42 | || requestCode == -1) {
43 | return;
44 | }
45 |
46 | List list = findListByKey(activity);
47 | list.add(new RequestArgs(requestCode, callback));
48 | }
49 |
50 | boolean dispatchActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
51 | if (!container.containsKey(activity)) {
52 | return false;
53 | }
54 |
55 | boolean handle = false;
56 | List list = findListByKey(activity);
57 | for (RequestArgs args:list) {
58 | if (args.requestCode == requestCode) {
59 | args.callback.onResult(resultCode, data);
60 | list.remove(args);
61 | handle = true;
62 | break;
63 | }
64 | }
65 |
66 | releaseInvalidItems();
67 | return handle;
68 | }
69 |
70 | // 移除无效的条目:比如当前activity在后台时被回收了
71 | private void releaseInvalidItems() {
72 | Set keys = container.keySet();
73 | Iterator iterator = keys.iterator();
74 | while (iterator.hasNext()) {
75 | Activity next = iterator.next();
76 | if (next.isFinishing()
77 | || container.get(next).isEmpty()
78 | || (Build.VERSION.SDK_INT >= 17 && next.isDestroyed()) ) {
79 | iterator.remove();
80 | }
81 | }
82 | }
83 |
84 | List findListByKey(Activity activity) {
85 | List list = container.get(activity);
86 | if (list == null) {
87 | list = new ArrayList<>();
88 | container.put(activity, list);
89 | }
90 | return list;
91 | }
92 |
93 | private static class RequestArgs {
94 | int requestCode;
95 | ActivityResultCallback callback;
96 |
97 | public RequestArgs(int requestCode, ActivityResultCallback callback) {
98 | this.requestCode = requestCode;
99 | this.callback = callback;
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/BundleFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import android.os.Bundle;
19 |
20 | import com.lzh.compiler.parceler.annotation.BundleConverter;
21 |
22 | import java.lang.reflect.Type;
23 |
24 | /**
25 | * 提供的用于操作{@link Bundle}数据源的处理入口类。
26 | *
27 | * @author haoge
28 | */
29 | public final class BundleFactory {
30 |
31 | /* 默认的数据转换器。通过{@link Parceler#setDefaultConverter(Class)}进行设置*/
32 | static Class extends BundleConverter> DEFAULT_CONVERTER = null;
33 | /* 用于进行操作的bundle实例*/
34 | private Bundle bundle;
35 | /* 指定是否略过异常。*/
36 | private boolean ignoreException = false;
37 | private Class extends BundleConverter> converter;
38 | private boolean forceConvert;
39 |
40 | BundleFactory(Bundle bundle) {
41 | if (bundle == null) {
42 | bundle = new Bundle();
43 | }
44 | this.bundle = bundle;
45 | }
46 |
47 | /**
48 | * 设置使用的数据转换器。若设置为null则表示使用通过{@link Parceler#setDefaultConverter(Class)}所设置的默认转换器,
49 | *
50 | *
51 | * 数据转换器的作用。分为两点:
52 | *
53 | * -
54 | * 当使用{@link #put(String, Object)}将数据添加入Bundle数据容器。若指定添加的数据类型不能直接被放入{@link Bundle}中,
55 | * 则通过此数据转换器的{@link BundleConverter#convertToBundle(Object)}方法对数据进行转换后再放入{@link Bundle}中。
56 | *
57 | * -
58 | * 当使用{@link #get(String, Type)}或{@link #get(String, Class)}将数据从Bundle数据中读取出来时。
59 | * 若根据指定key值读取出来的数据类型与指定的数据类型不匹配。则将通过{@link BundleConverter#convertToEntity(Object, Type)}进行对应转换
60 | *
61 | *
62 | *
63 | *
64 | * @param converter 数据转换器的class。请注意转换器一定需要提供一个空的无参构造器。
65 | * @return itself
66 | * @see BundleConverter
67 | */
68 | public BundleFactory setConverter(Class extends BundleConverter> converter) {
69 | this.converter = converter;
70 | return this;
71 | }
72 |
73 | /**
74 | *
75 | * 指定在使用{@link #put(String, Object)}将数据存储入Bundle数据容器中时。是否在进行类型判断前强制要求对添加的数据源进行转换。
76 | *
77 | *
78 | * 请注意:此标记位起作用的前提条件包括:
79 | *
80 | * - 含有有效的可用的数据转换器。
81 | * - 需要存储的数据源类型为非基本数据类型
82 | *
83 | *
84 | * @param forceConvert 是否强制进行转换。
85 | * @return itself
86 | */
87 | public BundleFactory setForceConvert(boolean forceConvert) {
88 | this.forceConvert = forceConvert;
89 | return this;
90 | }
91 |
92 | /**
93 | * 设置是否忽略操作过程中的异常。
94 | * @param ignoreException ignore 当设置为true时。则在操作过程中若出现异常。将不会将此异常抛出。
95 | * @return itself
96 | */
97 | public BundleFactory ignoreException(boolean ignoreException) {
98 | this.ignoreException = ignoreException;
99 | return this;
100 | }
101 |
102 | /**
103 | * 使用key值将数据源data放入bundle中进行存储
104 | *
105 | * @param key
106 | * 用于放置数据的key non-null
107 | * @param data
108 | * 被放置的数据 non-null
109 | * @return itself
110 | * @see #setConverter(Class)
111 | * @see #setForceConvert(boolean)
112 | * @see #putInternal(String, Object, Class, boolean)
113 | */
114 | public BundleFactory put(String key, Object data) {
115 | return putInternal(key, data, converter == null ? DEFAULT_CONVERTER : converter, forceConvert);
116 | }
117 |
118 | /**
119 | *
120 | * 使用key值将数据源data放入bundle中进行存储
121 | *
122 | * @param key
123 | * 用于放置数据的key non-null
124 | * @param data
125 | * 被放置的数据 non-null
126 | * @param converterClass
127 | * 数据转换器. 当数据源data的数据类型不能被直接放入{@link Bundle}中时。将会使用此转换器对数据源data进行数据转换。并将转换后的数据放入{@link Bundle}中
128 | * @param forceConvert
129 | * 是否强制要求进行转换。若设置为true, 且转换器不为null时。将强制先对数据源使用转换器进行转换后再放入Bundle中。
130 | * @return itself
131 | * @see BundleConverter
132 | * @see #setForceConvert(boolean)
133 | */
134 | private BundleFactory putInternal(String key, Object data, Class extends BundleConverter> converterClass, boolean forceConvert) {
135 | if (key == null || data == null) {
136 | return this;
137 | }
138 |
139 | try {
140 | BundleConverter converter = CacheManager.transformConverter(converterClass);
141 | if (forceConvert && converter != null && !Utils.isBaseType(data.getClass())) {
142 | data = converter.convertToBundle(data);
143 | converter = null;
144 | }
145 | BundleHandle.get().toBundle(bundle, key, data, converter);
146 | } catch (Throwable t) {
147 | if (!ignoreException) {
148 | throw t;
149 | }
150 | }
151 | return this;
152 | }
153 |
154 | /**
155 | * 从数据源中取出指定key的数据。使用默认转换器
156 | * @see #getInternal(String, Type, Class)
157 | */
158 | public T get(String key, Class type) {
159 | try {
160 | return get(key, ((Type) type));
161 | } catch (ClassCastException cast) {
162 | if (!ignoreException) {
163 | throw cast;
164 | }
165 | return null;
166 | }
167 | }
168 |
169 | /**
170 | * 从数据源中取出指定key的数据。使用默认转换器
171 | * @see #getInternal(String, Type, Class)
172 | */
173 | public T get(String key, Type type) {
174 | try {
175 | //noinspection unchecked
176 | return (T) getInternal(key, type, converter == null ? DEFAULT_CONVERTER : converter);
177 | } catch (ClassCastException cast) {
178 | if (!ignoreException) {
179 | throw cast;
180 | }
181 | return null;
182 | }
183 | }
184 |
185 | /**
186 | * 从数据源bundle中读取指定key值的数据。将其转换为对应type的对象实例并返回。
187 | *
188 | * @param key 用于从数据源中读取数据的指定key值
189 | * @param type 指定该数据应以怎样的数据类型进行返回。
190 | * @param converterClass 数据转换器。当从{@link Bundle}数据源中使用指定key获取的数据类型与指定type不匹配时。
191 | * 将使用此数据转换器将数据转换为指定type的数据类型实例。
192 | * @return 最终获取的数据。
193 | * @see BundleConverter
194 | */
195 | private Object getInternal(String key, Type type, Class extends BundleConverter> converterClass) {
196 | Object data = bundle.get(key);
197 | if (data == null || type == null) {
198 | return null;
199 | }
200 |
201 | try {
202 | BundleConverter converter = CacheManager.transformConverter(converterClass);
203 | //noinspection unchecked
204 | return BundleHandle.get().cast(data, type, converter);
205 | } catch (Throwable t) {
206 | if (!ignoreException) {
207 | throw t;
208 | }
209 | return null;
210 | }
211 | }
212 |
213 | /**
214 | * 获取数据源。
215 | *
216 | * @return 被操作的数据源实例。non-null.
217 | */
218 | public Bundle getBundle() {
219 | return bundle;
220 | }
221 |
222 |
223 | }
224 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/BundleHandle.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import android.os.Build;
19 | import android.os.Bundle;
20 | import android.os.IBinder;
21 | import android.os.Parcelable;
22 | import android.text.TextUtils;
23 | import android.util.Size;
24 | import android.util.SizeF;
25 | import android.util.SparseArray;
26 |
27 | import com.lzh.compiler.parceler.annotation.BundleConverter;
28 |
29 | import java.io.Serializable;
30 | import java.lang.reflect.ParameterizedType;
31 | import java.lang.reflect.Type;
32 | import java.util.ArrayList;
33 | import java.util.Collection;
34 |
35 | /**
36 | * 此类只应被{@link BundleFactory}使用。用于真正从{@link Bundle}数据源中读取或者存储数据。
37 | *
38 | * @author haoge
39 | */
40 | final class BundleHandle {
41 | private static BundleHandle handle = new BundleHandle();
42 | private BundleHandle () {}
43 | static BundleHandle get() {
44 | return handle;
45 | }
46 |
47 | /**
48 | * 将任意类型数据data使用key放入Bundle中。
49 | *
50 | *
51 | * - 如果data的数据类型能直接被放入{@link Bundle}, 则直接放入
52 | * - 如果data的数据类型不能直接被放入{@link Bundle}, 则使用转换器进行数据转换再放入
53 | *
54 | *
55 | * @param bundle 用于存储数据的容器.
56 | * @param key 用于存储数据的key值
57 | * @param data 需要被放置的数据data
58 | * @param converter 数据转换器实例
59 | */
60 | void toBundle(Bundle bundle, String key, Object data, BundleConverter converter) {
61 | try {
62 | toBundleInternal(bundle, key, data);
63 | } catch (Throwable t) {
64 | if (converter != null) {
65 | data = converter.convertToBundle(data);
66 | toBundle(bundle, key, data, null);
67 | } else {
68 | throw t;
69 | }
70 | }
71 | }
72 |
73 | private void toBundleInternal(Bundle bundle, String key, Object data) {
74 | Class> type = data.getClass();
75 | if (type.isAssignableFrom(int.class)
76 | || data.getClass().isAssignableFrom(Integer.class)) {
77 | bundle.putInt(key, (Integer) data);
78 | } else if (type.isAssignableFrom(boolean.class)
79 | || type.isAssignableFrom(Boolean.class)) {
80 | bundle.putBoolean(key, (Boolean) data);
81 | } else if (type.isAssignableFrom(byte.class)
82 | || type.isAssignableFrom(Byte.class)) {
83 | bundle.putByte(key, (Byte) data);
84 | } else if (type.isAssignableFrom(char.class)
85 | || type.isAssignableFrom(Character.class)) {
86 | bundle.putChar(key, (Character) data);
87 | } else if (type.isAssignableFrom(long.class)
88 | || type.isAssignableFrom(Long.class)) {
89 | bundle.putLong(key, (Long) data);
90 | } else if (type.isAssignableFrom(float.class)
91 | || type.isAssignableFrom(Float.class)) {
92 | bundle.putFloat(key, (Float) data);
93 | } else if (type.isAssignableFrom(double.class)
94 | || type.isAssignableFrom(Double.class)) {
95 | bundle.putDouble(key, (Double) data);
96 | } else if (type.isAssignableFrom(byte[].class)) {
97 | bundle.putByteArray(key, (byte[]) data);
98 | } else if (type.isAssignableFrom(char[].class)) {
99 | bundle.putCharArray(key, (char[]) data);
100 | } else if (type.isAssignableFrom(int[].class)) {
101 | bundle.putIntArray(key, (int[]) data);
102 | } else if (type.isAssignableFrom(long[].class)) {
103 | bundle.putLongArray(key, (long[]) data);
104 | } else if (type.isAssignableFrom(float[].class)) {
105 | bundle.putFloatArray(key, (float[]) data);
106 | } else if (type.isAssignableFrom(double[].class)) {
107 | bundle.putDoubleArray(key, (double[]) data);
108 | } else if (type.isAssignableFrom(boolean[].class)) {
109 | bundle.putBooleanArray(key, (boolean[]) data);
110 | } else if (type.isAssignableFrom(String.class)) {
111 | bundle.putString(key, (String) data);
112 | } else if (type.isAssignableFrom(String[].class)) {
113 | bundle.putStringArray(key, (String[]) data);
114 | } else if (Bundle.class.isInstance(data)) {
115 | bundle.putBundle(key, (Bundle) data);
116 | } else if (IBinder.class.isInstance(data)
117 | && Build.VERSION.SDK_INT >= 18) {
118 | bundle.putBinder(key, (IBinder) data);
119 | } else if (data instanceof CharSequence) {
120 | bundle.putCharSequence(key, (CharSequence) data);
121 | } else if (data instanceof CharSequence[]) {
122 | bundle.putCharSequenceArray(key, (CharSequence[]) data);
123 | } else if (data instanceof Parcelable) {
124 | bundle.putParcelable(key, (Parcelable) data);
125 | } else if (data instanceof Parcelable[]) {
126 | bundle.putParcelableArray(key, (Parcelable[]) data);
127 | } else if (data instanceof Serializable
128 | && !(data instanceof Collection)
129 | && !data.getClass().isArray()) {
130 | bundle.putSerializable(key, (Serializable) data);
131 | } else if (Build.VERSION.SDK_INT > 21
132 | && data instanceof Size) {
133 | bundle.putSize(key, (Size) data);
134 | } else if (Build.VERSION.SDK_INT > 21
135 | && data instanceof SizeF) {
136 | bundle.putSizeF(key, (SizeF) data);
137 | } else {
138 | toBundleFromGenericType(bundle, key, data);
139 | }
140 |
141 | }
142 |
143 | @SuppressWarnings("unchecked")
144 | private boolean toBundleFromArrayList(Bundle bundle, String key, ArrayList list) {
145 | if (list.isEmpty()) {
146 | bundle.putIntegerArrayList(key, list);
147 | return true;
148 | }
149 |
150 | boolean handle = false;
151 | Object item = list.get(0);
152 | if (item instanceof Integer) {
153 | bundle.putIntegerArrayList(key, list);
154 | handle = true;
155 | } else if (item instanceof Parcelable) {
156 | bundle.putParcelableArrayList(key, list);
157 | handle = true;
158 | } else if (item instanceof String) {
159 | bundle.putStringArrayList(key, list);
160 | handle = true;
161 | } else if (item instanceof CharSequence) {
162 | bundle.putCharSequenceArrayList(key, list);
163 | handle = true;
164 | }
165 |
166 | return handle;
167 | }
168 |
169 | @SuppressWarnings("unchecked")
170 | private boolean toBundleFromSparseArray(Bundle bundle, String key, SparseArray list) {
171 | if (list.size() == 0) {
172 | bundle.putSparseParcelableArray(key, list);
173 | return true;
174 | }
175 |
176 | // extract item from first index and to check it if is supported.
177 | Object item = list.get(list.keyAt(0));
178 | if (item instanceof Parcelable) {
179 | bundle.putSparseParcelableArray(key, list);
180 | return true;
181 | }
182 |
183 | return false;
184 | }
185 |
186 | @SuppressWarnings({"unchecked", "ConstantConditions"})
187 | private void toBundleFromGenericType(Bundle bundle, String key, Object data) {
188 | if ((data instanceof ArrayList) && toBundleFromArrayList(bundle, key, (ArrayList) data)) {
189 | return;
190 | }
191 | if (data instanceof SparseArray && toBundleFromSparseArray(bundle, key, (SparseArray) data)) {
192 | return;
193 | }
194 | throw new RuntimeException("Could not put data to bundle");
195 | }
196 |
197 | /**
198 | * 将指定数据data转换为指定类型type数据并返回。
199 | *
200 | *
201 | * - 当data能直接与数据类型type匹配时,直接返回原始数据data
202 | * - 当data不能与type匹配时,使用数据转换器对原始数据data进行转换后再返回。
203 | *
204 | *
205 | * @param data 指定的数据data
206 | * @param type 指定数据类型type
207 | * @param converter 数据转换器
208 | * @return 转换后的指定type类型的数据。
209 | */
210 | Object cast(Object data, Type type, BundleConverter converter) {
211 | return castInternal(data, type, converter);
212 | }
213 |
214 | private Object castInternal(Object data, Type type, BundleConverter converter) {
215 | Class raw = getRawClass(type);
216 | if (raw.isInstance(data)) return data;
217 |
218 | if (!(data instanceof String)) {
219 | if (converter == null) {
220 | throw new RuntimeException("Should only handle with String. Please check if you had set a converter to used?");
221 | } else {
222 | data = converter.convertToBundle(data);
223 | }
224 | }
225 |
226 | String value = (String) data;
227 | if (TextUtils.isEmpty(value)) {
228 | return returnsValue(null, raw);
229 | }
230 |
231 | switch (raw.getCanonicalName()) {
232 | case "byte":
233 | case "java.lang.Byte":
234 | return Byte.valueOf(value);
235 | case "short":
236 | case "java.lang.Short":
237 | return Short.valueOf(value);
238 | case "int":
239 | case "java.lang.Integer":
240 | return Integer.valueOf(value);
241 | case "long":
242 | case "java.lang.Long":
243 | return Long.valueOf(value);
244 | case "float":
245 | case "java.lang.Float":
246 | return Float.valueOf(value);
247 | case "double":
248 | case "java.lang.Double":
249 | return Double.valueOf(value);
250 | case "char":
251 | case "java.lang.Character":
252 | return value.charAt(0);
253 | case "boolean":
254 | case "java.lang.Boolean":
255 | return Boolean.valueOf(value);
256 | case "java.lang.StringBuffer":
257 | return new StringBuffer(value);
258 | case "java.lang.StringBuilder":
259 | return new StringBuilder(value);
260 | default:
261 | if (converter != null) {
262 | return converter.convertToEntity(value, type);
263 | } else {
264 | return returnsValue(null, raw);
265 | }
266 | }
267 | }
268 |
269 | // 兼容基本数据类型返回,对返回数据进行二次处理。避免对基本数据类型返回null导致crash
270 | private Object returnsValue(Object value, Class type) {
271 | if (value != null) return value;
272 |
273 | switch (type.getCanonicalName()) {
274 | case "byte":
275 | case "short":
276 | case "int":
277 | return 0;
278 | case "long":
279 | return 0L;
280 | case "float":
281 | return 0f;
282 | case "double":
283 | return 0d;
284 | case "char":
285 | return '0';
286 | case "boolean":
287 | return false;
288 | default:
289 | return null;
290 | }
291 | }
292 |
293 | private Class getRawClass(Type type) {
294 | if (type instanceof Class) {
295 | return (Class) type;
296 | } else if (type instanceof ParameterizedType) {
297 | return getRawClass(((ParameterizedType) type).getRawType());
298 | } else {
299 | throw new RuntimeException("Only support of Class and ParameterizedType");
300 | }
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/CacheManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import com.lzh.compiler.parceler.annotation.BundleConverter;
19 |
20 | import java.lang.reflect.Field;
21 | import java.lang.reflect.Type;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 |
25 | /**
26 | * 缓存管理器。用于对一些类进行缓存处理。达到运行加速的效果
27 | * @author haoge
28 | */
29 | public final class CacheManager {
30 |
31 | /* 数据转换器容器: 存储所有使用过的有效的转换器实例。避免多次进行创建*/
32 | private final static Map CONVERTER_CONTAINERS = new HashMap<>();
33 | /* 实体类中字段数据类型容器:避免每次进行注入的时候都去反射读取*/
34 | private final static Map> TYPES = new HashMap<>();
35 |
36 | static BundleConverter transformConverter(Class extends BundleConverter> converterClass) {
37 | if (converterClass == null) {
38 | return null;
39 | }
40 | BundleConverter converter = CONVERTER_CONTAINERS.get(converterClass);
41 | if (converter == null) {
42 | try {
43 | converter = converterClass.newInstance();
44 | CONVERTER_CONTAINERS.put(converterClass, converter);
45 | } catch (Throwable e) {
46 | throw new RuntimeException(String.format("The subclass of BundleConverter %s should provided an empty construct method.", converterClass), e);
47 | }
48 | }
49 | return converter;
50 | }
51 |
52 | /**
53 | * 获取数据实体类entity中指定字段名fieldName的字段的数据类型。
54 | * @param fieldName 字段名
55 | * @param entity 实体类
56 | * @return 反射获取到的真实的数据类型。
57 | */
58 | public static Type findType(String fieldName, Class entity) {
59 | Map fieldsMap = TYPES.get(entity);
60 | if (fieldsMap == null) {
61 | fieldsMap = new HashMap<>();
62 | Field[] fields = entity.getDeclaredFields();
63 | for (Field field : fields) {
64 | fieldsMap.put(field.getName(), field.getGenericType());
65 | }
66 | TYPES.put(entity, fieldsMap);
67 | }
68 | return fieldsMap.get(fieldName);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | /**
19 | *
20 | * @author haoge
21 | */
22 | class Constants {
23 |
24 | /**
25 | * 生成的注入器的类名后缀。
26 | */
27 | static final String SUFFIX = "BundleInjector";
28 | /**
29 | * 需要被过滤包名前缀。
30 | */
31 | static final String[] FILTER_PREFIX = new String[]{
32 | "com.android",
33 | "android",
34 | "java",
35 | "javax",
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/IBundleBuilder.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler;
2 |
3 | import android.os.Bundle;
4 |
5 | public interface IBundleBuilder {
6 |
7 | Class getTarget();
8 |
9 | Bundle build();
10 |
11 | BundleFactory getFactory();
12 | }
13 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/IntentLauncher.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler;
2 |
3 | import android.app.Activity;
4 | import android.app.Service;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.os.Build;
9 | import android.os.Bundle;
10 |
11 | import java.util.Random;
12 |
13 | /**
14 | * 用于配合BundleBuilder生成类进行使用的启动器。可用于进行Activity/Service/BroadcastReceiver启动。
15 | * @author haoge on 2017/12/26.
16 | */
17 | public class IntentLauncher {
18 |
19 | private ActivityResultCallback callback;
20 | private int requestCode = -1;
21 | private Bundle options;
22 | private Bundle bundle;
23 | private Class> target;
24 | private Intent extra;
25 |
26 | private static Random sCodeGenerator;
27 |
28 | private IntentLauncher(Bundle bundle, Class> target) {
29 | this.bundle = bundle;
30 | this.target = target;
31 | }
32 |
33 | /**
34 | * 创建一个Intent启动器。此启动器关联此Builder类。
35 | *
36 | * 此Builder实例用于提供传输的Bundle数据。以及所关联的目标类:{@link IBundleBuilder#getTarget()}。
37 | *
38 | *
目前此此启动器所支持的关联目标类包括Activity、Service以及BroadcastReceiver的子类。
39 | *
40 | * @param builder 提供数据的Builder
41 | */
42 | static IntentLauncher create(IBundleBuilder builder) {
43 | return new IntentLauncher(builder.build(), builder.getTarget());
44 | }
45 |
46 | static IntentLauncher create(Bundle bundle, Class> target) {
47 | return new IntentLauncher(bundle, target);
48 | }
49 |
50 | /**
51 | * 设置startActivity时所需要的requestCode。对应{@link Activity#startActivityForResult(Intent, int)}
52 | *
53 | * @param requestCode 请求码
54 | */
55 | public IntentLauncher setRequestCode(int requestCode) {
56 | this.requestCode = requestCode;
57 | return this;
58 | }
59 |
60 | /**
61 | * 设置在onActivityResult时使用的回调。
62 | * @param callback callback
63 | */
64 | public IntentLauncher setResultCallback(ActivityResultCallback callback) {
65 | this.callback = callback;
66 | return this;
67 | }
68 |
69 | /**
70 | * 设置startActivity时所需要的options参数。对应{@link Activity#startActivityForResult(Intent, int, Bundle)}
71 | * @param options {@link Activity#startActivityForResult(Intent, int, Bundle)}
72 | */
73 | public IntentLauncher setOptions(Bundle options) {
74 | this.options = options;
75 | return this;
76 | }
77 |
78 | /**
79 | * 设置Intent镜像。在进行Intent创建时。若设置的extra Intent不为null。则将对此intent实例进行clone并替换Classname提供使用
80 | * @param intent Intent镜像
81 | */
82 | public IntentLauncher setExtra(Intent intent) {
83 | this.extra = intent;
84 | return this;
85 | }
86 |
87 | /**
88 | * 根据之前配置的数据,获取所需要的Intent实例。
89 | */
90 | public Intent getIntent(Context context) {
91 | if (context == null) {
92 | return null;
93 | }
94 |
95 | Class> target = this.target;
96 | if (!Activity.class.isAssignableFrom(target)
97 | && !Service.class.isAssignableFrom(target)
98 | && !BroadcastReceiver.class.isAssignableFrom(target)) {
99 | return null;
100 | }
101 |
102 | Intent intent;
103 | if (extra != null) {
104 | intent = new Intent(extra);
105 | intent.setClass(context, target);
106 | extra = null;
107 | } else {
108 | intent = new Intent(context, target);
109 | }
110 | intent.putExtras(this.bundle);
111 | return intent;
112 | }
113 |
114 | /**
115 | * 使用此Context实例。根据对{@link IBundleBuilder#getTarget()}的类型判断,进行Intent启动。
116 | *
117 | *
118 | * -
119 | * 当类型为Activity的子类,则根据context是否为Activity实例。使用
120 | * {@link Activity#startActivityForResult(Intent, int, Bundle)}或者{@link Context#startActivity(Intent)}
121 | * 进行启动
122 | *
123 | * - 当类型为Service的子类,则使用{@link Context#startService(Intent)}进行启动
124 | * - 当类型为BroadcastReceiver的子类,则使用{@link Context#sendBroadcast(Intent)}进行启动
125 | * - 当需要
126 | *
127 | */
128 | public void start(Context context) {
129 | if (context == null) {
130 | return;
131 | }
132 | Intent intent = getIntent(context);
133 | Class> target = this.target;
134 |
135 | if (Activity.class.isAssignableFrom(target)) {
136 | startActivity(context, intent);
137 | } else if (Service.class.isAssignableFrom(target)) {
138 | context.startService(intent);
139 | } else if (BroadcastReceiver.class.isAssignableFrom(target)) {
140 | context.sendBroadcast(intent);
141 | }
142 | }
143 |
144 | private void startActivity(Context context, Intent intent) {
145 | if (context instanceof Activity) {
146 | if (callback != null && requestCode == -1) {
147 | requestCode = sCodeGenerator.nextInt(0x0000FFFF);
148 | }
149 | Activity activity = (Activity) context;
150 | if (options != null && Build.VERSION.SDK_INT >= 16) {
151 | activity.startActivityForResult(intent, requestCode, options);
152 | } else {
153 | activity.startActivityForResult(intent, requestCode);
154 | }
155 | ActivityResultDispatcher.get().bindRequestArgs(activity, requestCode, callback);
156 | } else {
157 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
158 | context.startActivity(intent);
159 | }
160 | }
161 |
162 | static {
163 | sCodeGenerator = new Random();
164 | }
165 |
166 | }
167 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/ParcelInjector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import android.os.Bundle;
19 |
20 | import com.lzh.compiler.parceler.annotation.Arg;
21 |
22 | /**
23 | * 请不要直接手动实现此接口
24 | *
25 | *
26 | * 此接口用于定义注入的数据流的两种方向:
27 | *
28 | * - 将数据从实体类中注入{@link Bundle}: {@link #toBundle(Object, Bundle)}
29 | * - 将数据从{@link Bundle}中注入实体类: {@link #toEntity(Object, Bundle)}
30 | *
31 | *
32 | *
33 | *
34 | * 此接口不应由外部直接实现使用。正常情况下。此接口应有如下两种实现类:
35 | *
36 | * - 根据使用了{@link Arg}注解的实体类编译时生成对应的注入器实现类:生成类名=实体类名+{@link Constants#SUFFIX}
37 | * - 默认提供的在非APT环境下使用的{@link RuntimeInjector}
38 | *
39 | *
40 | *
41 | * @param 使用的实体类泛型
42 | *
43 | * @see RuntimeInjector
44 | * @author haoge
45 | */
46 | public interface ParcelInjector {
47 |
48 | /**
49 | * 用于从Bundle数据容器中,取出数据并注入到实体类中对应的被{@link Arg}所注解的字段中去。
50 | * @param entity 被注入的实体类对象。
51 | * @param bundle {@link Bundle}数据容器
52 | */
53 | void toEntity(T entity,Bundle bundle);
54 |
55 | /**
56 | * 用于从实体类entity中,将对应的被{@link Arg}注解过的字段的值。注入到Bundle数据容器中。
57 | * @param entity 实体类entity
58 | * @param bundle Bundle数据容器
59 | */
60 | void toBundle(T entity, Bundle bundle);
61 |
62 | /**
63 | * 提供一个空实现的注入器。用于提供出去避免空指针
64 | */
65 | ParcelInjector NONE_INJECTOR = new ParcelInjector() {
66 | @Override
67 | public void toEntity(Object entity, Bundle bundle) {}
68 |
69 | @Override
70 | public void toBundle(Object entity, Bundle bundle) {}
71 | };
72 |
73 | /**
74 | * 提供一个运行时的注入器。用于当未找到编译时生成的注入器时进行使用。
75 | */
76 | ParcelInjector RUNTIME_INJECTOR = RuntimeInjector.get();
77 | }
78 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/Parceler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import android.app.Activity;
19 | import android.content.Intent;
20 | import android.os.Bundle;
21 |
22 | import com.lzh.compiler.parceler.annotation.BundleConverter;
23 |
24 | import java.lang.ref.WeakReference;
25 | import java.util.HashMap;
26 | import java.util.Map;
27 |
28 | /**
29 | * 框架入口类。对外提供的功能的入口都在此类中。功能包括以下几点:
30 | *
31 | *
32 | * -
33 | * 将数据从任意实体类注入到数据容器{@link Bundle}中:{@link #toBundle(Object, Bundle)}
34 | *
35 | * -
36 | * 将数据从数据容器{@link Bundle}中注入到对应实体类中:使用{@link #toEntity(Object, Intent)}或者{@link #toEntity(Object, Bundle)}
37 | *
38 | * -
39 | * 创建Bundle数据处理工厂。对{@link Bundle}数据进行灵活存取:{@link #createFactory(Bundle)}
40 | *
41 | * -
42 | * 设置默认的数据转换器:{@link #setDefaultConverter(Class)}
43 | *
44 | *
45 | * @author haoge
46 | */
47 | public final class Parceler {
48 |
49 | /* 缓存的注入器,加速操作。*/
50 | private static Map> INJECTORS = new HashMap<>();
51 |
52 | /**
53 | * 将数据从数据容器{@link Bundle}中注入到对应实体类中
54 | * @see #toEntity(Object, Bundle)
55 | */
56 | public static T toEntity(T entity, Intent intent) {
57 | return toEntity(entity,intent == null ? null : intent.getExtras());
58 | }
59 |
60 | /**
61 | * 将数据从数据容器{@link Bundle}中注入到对应实体类中:
62 | *
63 | *
64 | * 此注入方式依赖于数据注入器{@link ParcelInjector}实现。
65 | * 注入器的获取方式请参考:{@link #getInjectorByClass(Class)}方法
66 | *
67 | *
68 | * @param 实体类泛型
69 | * @param entity 需要被注入数据的实体类。non-null
70 | * @param data Bundle数据容器。non-null
71 | *
72 | * @return 返回被注入操作后的entity实例。
73 | */
74 | public static T toEntity(T entity, Bundle data) {
75 | if (entity == null || data == null) return entity;
76 |
77 | ParcelInjector injector;
78 | try {
79 | injector = getInjectorByClass(entity.getClass());
80 | //noinspection unchecked
81 | injector.toEntity(entity,data);
82 | } catch (Throwable e) {
83 | throw new RuntimeException(String.format("inject failed : %s",e.getMessage()),e);
84 | }
85 | return entity;
86 | }
87 |
88 | /**
89 | * 将数据从实体类entity中读取,并注入到{@link Bundle}数据中。
90 | *
91 | *
92 | * 此注入方式依赖于数据注入器{@link ParcelInjector}实现。
93 | * 注入器的获取方式请参考:{@link #getInjectorByClass(Class)}方法
94 | *
95 | *
96 | * @param entity 需要被注入数据的实体类。non-null
97 | * @param data Bundle数据容器。non-null
98 | *
99 | * @return 返回被注入操作后的Bundle实例。
100 | */
101 | public static Bundle toBundle(Object entity, Bundle data) {
102 | if (entity == null || data == null) return data;
103 |
104 | ParcelInjector injector;
105 | try {
106 | injector = getInjectorByClass(entity.getClass());
107 | //noinspection unchecked
108 | injector.toBundle(entity,data);
109 | } catch (Throwable e) {
110 | throw new RuntimeException(String.format("inject failed : %s",e.getMessage()),e);
111 | }
112 | return data;
113 | }
114 |
115 | /**
116 | * internal api: 用于提供给通过编译时注解生成的注入器类进行使用。外部请不要调用
117 | *
118 | * 根据指定class获取其父类的通过编译时注解生成的注入器实例。或者返回{@link ParcelInjector#NONE_INJECTOR}
119 | *
120 | * @param clz 指定的class
121 | * @return 找到的注入器实例,non-null
122 | * @see ParcelInjector
123 | */
124 | public static ParcelInjector getParentInjectorByClass (Class clz) {
125 | try {
126 | ParcelInjector injector = getInjectorByClass(clz.getSuperclass());
127 | // filters runtime injector.
128 | if (injector instanceof RuntimeInjector) {
129 | injector = ParcelInjector.NONE_INJECTOR;
130 | }
131 | return injector;
132 | } catch (Throwable e) {
133 | return ParcelInjector.NONE_INJECTOR;
134 | }
135 | }
136 |
137 | /**
138 | *
根据指定class找到对应匹配的注入器. 注入器根据以下获取方式以先后顺序进行获取。
139 | *
140 | *
141 | * -
142 | * 根据class类名匹配在编译时通过APT方式生成的注入器类对象。若没有。则向上进行父类class的匹配。
143 | * 匹配规则:注入器生成类名具备一定规则:生成器类名=class类型+{@link Constants#SUFFIX}.
144 | *
145 | * -
146 | * 当没有匹配到对应的编译时生成的注入器时。提供框架提供的默认的{@link RuntimeInjector}类实例进行使用。
147 | *
148 | *
149 | *
150 | * @param clz 指定的用于匹配的class
151 | * @return 通过指定class匹配到的注入器类对象。non-null
152 | *
153 | * @see ParcelInjector
154 | */
155 | private static ParcelInjector getInjectorByClass(Class clz) throws IllegalAccessException, InstantiationException {
156 | ParcelInjector injector;
157 | if (INJECTORS.containsKey(clz) && (injector = INJECTORS.get(clz).get()) != null) {
158 | return injector;
159 | }
160 | String clzName = clz.getName() + Constants.SUFFIX;
161 |
162 | for (String prefix : Constants.FILTER_PREFIX) {
163 | if (clzName.startsWith(prefix)) {
164 | INJECTORS.put(clz,new WeakReference<>(ParcelInjector.RUNTIME_INJECTOR));
165 | return ParcelInjector.RUNTIME_INJECTOR;
166 | }
167 | }
168 |
169 | try {
170 | Class> injectorClz = Class.forName(clzName);
171 | injector = (ParcelInjector) injectorClz.newInstance();
172 | INJECTORS.put(clz,new WeakReference<>(injector));
173 | return injector;
174 | } catch (ClassNotFoundException e) {
175 | injector = getInjectorByClass(clz.getSuperclass());
176 | INJECTORS.put(clz,new WeakReference<>(injector));
177 | return injector;
178 | }
179 | }
180 |
181 | /**
182 | * 创建一个{@link BundleFactory}对象,以对Bundle数据进行处理操作
183 | * @param src 原始的{@link Bundle}数据源。当为null时,表示将使用一个新建的{@link Bundle}作为数据源进行操作
184 | * @return itself
185 | */
186 | public static BundleFactory createFactory(Bundle src) {
187 | return new BundleFactory(src);
188 | }
189 |
190 | public static IntentLauncher createLauncher(IBundleBuilder builder) {
191 | return IntentLauncher.create(builder);
192 | }
193 |
194 | public static IntentLauncher createLauncher(Class> target, Bundle bundle) {
195 | return IntentLauncher.create(bundle, target);
196 | }
197 |
198 | /**
199 | * 针对{@link BundleFactory}指定默认使用的数据转换器。
200 | * @param converter 默认使用的转换器class. 此class应含有一个默认的无参构造。便于框架需要使用的来构造使用。
201 | */
202 | public static void setDefaultConverter(Class extends BundleConverter> converter) {
203 | BundleFactory.DEFAULT_CONVERTER = converter;
204 | }
205 |
206 | public static boolean dispatchActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
207 | return ActivityResultDispatcher.get().dispatchActivityResult(activity, requestCode, resultCode, data);
208 | }
209 |
210 | private Parceler () {}
211 | }
212 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/RuntimeInjector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | import android.os.Bundle;
19 | import android.text.TextUtils;
20 |
21 | import com.lzh.compiler.parceler.annotation.Arg;
22 | import com.lzh.compiler.parceler.annotation.BundleConverter;
23 | import com.lzh.compiler.parceler.annotation.Converter;
24 |
25 | import java.lang.reflect.Field;
26 | import java.util.ArrayList;
27 | import java.util.HashMap;
28 | import java.util.List;
29 | import java.util.Map;
30 |
31 | /**
32 | * 提供一个完全基于反射使用的注入器。兼容非apt环境使用。
33 | */
34 | final class RuntimeInjector implements ParcelInjector{
35 |
36 | /* 缓存任意实体类与其内部所配置的Arg参数数据的映射表*/
37 | private final static Map> CONTAINER = new HashMap<>();
38 |
39 | private final static RuntimeInjector injector = new RuntimeInjector();
40 | private RuntimeInjector(){}
41 | public static RuntimeInjector get() {
42 | return injector;
43 | }
44 |
45 | @Override
46 | public void toEntity(Object entity, Bundle bundle) {
47 | List list = findByEntity(entity.getClass());
48 | BundleFactory factory = Parceler.createFactory(bundle);
49 | for (Args item:list) {
50 | Object result;
51 | factory.setConverter(item.converter);
52 | result = factory.get(item.key, item.field.getGenericType());
53 | if (result != null) {
54 | setFieldValue(entity, result, item.field);
55 | }
56 | }
57 | }
58 |
59 | @Override
60 | public void toBundle(Object entity, Bundle bundle) {
61 | BundleFactory factory = Parceler.createFactory(bundle);
62 | List list = findByEntity(entity.getClass());
63 | for (Args arg : list) {
64 | factory.setConverter(arg.converter);
65 | factory.put(arg.key, getFieldValue(entity, arg.field));
66 | }
67 | }
68 |
69 | private void setFieldValue(Object entity, Object result, Field field) {
70 | try {
71 | field.setAccessible(true);
72 | field.set(entity, result);
73 | } catch (Throwable t) {
74 | // ignore
75 | }
76 | }
77 |
78 | private Object getFieldValue(Object entity, Field field) {
79 | try {
80 | field.setAccessible(true);
81 | return field.get(entity);
82 | } catch (Throwable t) {
83 | return null;
84 | }
85 | }
86 |
87 | /**
88 | * 解析出实体类entity中(包括父类)。所有的被{@link Arg}所注解的字段数据。
89 | * @param entity 被解析的实体类class
90 | * @return 获取的数据
91 | */
92 | private List findByEntity(Class entity) {
93 | if (isSystemClass(entity)) {
94 | return new ArrayList<>();
95 | }
96 | List list = CONTAINER.get(entity);
97 | if (list == null) {
98 | list = new ArrayList<>();
99 | List subList = findByEntity(entity.getSuperclass());
100 | list.addAll(subList);
101 | Field[] fields = entity.getDeclaredFields();
102 | for (Field field : fields) {
103 | if (field.isAnnotationPresent(Arg.class)) {
104 | Arg arg = field.getAnnotation(Arg.class);
105 | Converter converter = field.getAnnotation(Converter.class);
106 | Args args = new Args();
107 | args.key = TextUtils.isEmpty(arg.value()) ? field.getName() : arg.value();
108 | args.field = field;
109 | args.converter = converter == null ? null : converter.value();
110 | list.add(args);
111 | }
112 | }
113 | CONTAINER.put(entity, list);
114 | }
115 | return list;
116 | }
117 |
118 | /* 过滤系统类。由于系统类不参与注入。过滤以加速运行*/
119 | private boolean isSystemClass(Class clz) {
120 | String clzName = clz.getCanonicalName();
121 | for (String prefix : Constants.FILTER_PREFIX) {
122 | if (clzName.startsWith(prefix)) {
123 | return true;
124 | }
125 | }
126 | return false;
127 | }
128 |
129 | private static class Args {
130 | String key;
131 | Field field;
132 | Class extends BundleConverter> converter;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/api/src/main/java/com/lzh/compiler/parceler/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 Haoge
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.lzh.compiler.parceler;
17 |
18 | public class Utils {
19 |
20 | /* Used for generated code.*/
21 | public static T wrapCast (Object data) {
22 | //noinspection unchecked
23 | return (T) data;
24 | }
25 |
26 | static boolean isBaseType(Class> clz) {
27 | return clz == Integer.class
28 | || clz == int.class
29 | || clz == boolean.class
30 | || clz == Boolean.class
31 | || clz == byte.class
32 | || clz == Byte.class
33 | || clz == char.class
34 | || clz == Character.class
35 | || clz == float.class
36 | || clz == Float.class
37 | || clz == double.class
38 | || clz == Double.class
39 | || clz == long.class
40 | || clz == Long.class;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 |
5 | android {
6 | compileSdkVersion 27
7 | buildToolsVersion '27.0.3'
8 | defaultConfig {
9 | applicationId "com.lzh.compiler.parcelerdemo"
10 | minSdkVersion 15
11 | targetSdkVersion 27
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | lintOptions {
16 | abortOnError false
17 | }
18 |
19 | buildTypes {
20 | debug {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | }
30 |
31 | def use_local = false
32 | def PARCELER_VERSION = '1.4.0'
33 | def Router_version = '2.8.3'
34 |
35 | dependencies {
36 | if (use_local) {
37 | kapt project(':compiler')
38 | implementation project(':api')
39 | } else {
40 | kapt "com.github.yjfnypeu.Parceler:compiler:$PARCELER_VERSION"
41 | implementation "com.github.yjfnypeu.Parceler:api:$PARCELER_VERSION"
42 | }
43 |
44 | implementation 'com.android.support:appcompat-v7:27.1.1'
45 | implementation 'com.alibaba:fastjson:1.1.57.android'
46 | implementation 'com.google.code.gson:gson:2.8.0'
47 |
48 | kapt "com.github.yjfnypeu.Router:router-compiler:$Router_version"
49 | implementation "com.github.yjfnypeu.Router:router-api:$Router_version"
50 |
51 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
52 |
53 | }
--------------------------------------------------------------------------------
/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/admin/Library/Android/sdk/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 | -dontwarn com.lzh.compiler.parceler.processor.**
19 | -dontwarn butterknife.**
20 | #Parceler混淆规则
21 | -keep class com.lzh.compiler.parceler.annotation.**
22 | -keep class * implements com.lzh.compiler.parceler.ParcelInjector
23 |
24 | -keepclasseswithmembernames class * {
25 | @com.lzh.compiler.parceler.annotation.Arg ;
26 | }
27 |
28 | #添加ButterKnife混淆规则
29 | -keep class butterknife.** { *; }
30 | -keep class **$$ViewBinder { *; }
31 |
32 | -keepclasseswithmembernames class * { @butterknife.* ; }
33 | -keepclasseswithmembernames class * { @butterknife.* ; }
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/BundleActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.TextView;
7 |
8 | import com.lzh.compiler.parceler.BundleFactory;
9 | import com.lzh.compiler.parceler.Parceler;
10 | import com.lzh.compiler.parceler.annotation.BundleBuilder;
11 | import com.lzh.compiler.parcelerdemo.bean.Book;
12 | import com.lzh.compiler.parcelerdemo.bean.Info;
13 | import com.lzh.compiler.parcelerdemo.bean.NormalUser;
14 | import com.lzh.compiler.parcelerdemo.bean.SerialUser;
15 |
16 | import java.lang.reflect.Type;
17 | import java.util.Set;
18 |
19 | /**
20 | * 此页面用于展示如何使用Parceler进行Bundle的数据存取操作。
21 | */
22 | @BundleBuilder
23 | public class BundleActivity extends Activity {
24 |
25 | BundleFactory factory;
26 | TextView result;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_bundle);
32 | factory = Parceler.createFactory(new Bundle());
33 | result = (TextView) findViewById(R.id.result);
34 | }
35 |
36 | public void putNormalData(View view) {
37 | factory.put("int", 1);
38 | factory.put("string", "Hello world");
39 | factory.put("parcelable", new Info());
40 | result.setText("存入普通数据成功");
41 | }
42 |
43 | public void putSpecialData(View view) {
44 | factory.put("book", new Book("逗逼是怎么炼成的", 66.66f));
45 | result.setText("存入特殊数据成功");
46 | }
47 |
48 | public void getDataWithoutParceler(View view) {
49 | Bundle bundle = factory.getBundle();
50 | Set keys = bundle.keySet();
51 |
52 | StringBuilder builder = new StringBuilder("不使用Parceler进行Bundle数据读取展示:");
53 | for (String key : keys) {
54 | builder.append("\r\n");
55 | builder.append(key + " = " + bundle.get(key));
56 | }
57 |
58 | result.setText(builder.toString());
59 | }
60 |
61 | public void getDataWithParceler(View view) {
62 | StringBuilder builder = new StringBuilder("使用Parceler进行Bundle数据读取展示:");
63 | resolveKeyValue(builder, "int", int.class);
64 | resolveKeyValue(builder, "string", String.class);
65 | resolveKeyValue(builder, "parcelable", Info.class);
66 | resolveKeyValue(builder, "book", Book.class);
67 | result.setText(builder.toString());
68 | }
69 |
70 | private void resolveKeyValue(StringBuilder builder, String key, Type type) {
71 | builder.append("\r\n");
72 | builder.append(key + " = " + factory.get(key, type));
73 | }
74 |
75 | public void testSerialAndNormalStore(View view) {
76 | NormalUser normalUser = new NormalUser();
77 | SerialUser serialUser = new SerialUser();
78 | normalUser.username = "this is normal user bean";
79 | serialUser.username = "this is serial user bean";
80 |
81 | BundleFactory factory = Parceler.createFactory(new Bundle());
82 | factory.put("normal", normalUser);
83 | factory.put("serial", serialUser);
84 |
85 | Bundle result = factory.getBundle();
86 |
87 | NormalUser newNormalUser = factory.get("normal", NormalUser.class);
88 | SerialUser newSerialUser = factory.get("serial", SerialUser.class);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/InjectorActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo;
2 |
3 | import android.os.Bundle;
4 | import android.view.View;
5 | import android.widget.TextView;
6 |
7 | import com.lzh.compiler.parceler.Parceler;
8 | import com.lzh.compiler.parceler.annotation.Arg;
9 | import com.lzh.compiler.parcelerdemo.base.BaseActivity;
10 |
11 | import java.util.Set;
12 |
13 | /**
14 | * 此页面用于演示使用Parceler在Bundle与Entity之间进行双向注入的展示
15 | */
16 | public class InjectorActivity extends BaseActivity {
17 |
18 | TextView result;
19 |
20 | @Override
21 | protected void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.activity_injector);
24 | result = (TextView) findViewById(R.id.result);
25 | }
26 |
27 | public void toEntity(View view) {
28 | Entity.User user = new Entity.User();
29 | user.username = "toEntity";
30 | user.password = "654321";
31 | Bundle bundle = Parceler.createFactory(null)
32 | .put("user", user)
33 | .getBundle();
34 |
35 | Entity entity = Parceler.toEntity(new Entity(), bundle);
36 | result.setText("toEntity:\r\n" + entity.toString());
37 | }
38 |
39 | public void toBundle(View view) {
40 | Entity.User user = new Entity.User();
41 | user.username = "toBundle";
42 | user.password = "123456";
43 | Entity entity = new Entity();
44 | entity.user = user;
45 |
46 | // 读取entity实例中被注解的字段并存入bundle中
47 | Bundle bundle = Parceler.toBundle(entity, new Bundle());
48 | // 打印bundle数据
49 | Set keys = bundle.keySet();
50 | StringBuilder builder = new StringBuilder("toBundle:");
51 | for (String key : keys) {
52 | builder.append("\r\n");
53 | builder.append(key + "= " + bundle.get(key));
54 | }
55 | result.setText(builder.toString());
56 | }
57 |
58 |
59 | public static class Entity {
60 | @Arg
61 | public User user;
62 |
63 | public static class User {
64 | @Arg
65 | public String username;
66 | @Arg
67 | public String password;
68 |
69 | @Override
70 | public String toString() {
71 | return "User{" +
72 | "username='" + username + '\'' +
73 | ", password='" + password + '\'' +
74 | '}';
75 | }
76 | }
77 |
78 | @Override
79 | public String toString() {
80 | return "Entity{" +
81 | "user=" + user +
82 | '}';
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/KotlinLoginActivity.kt:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo
2 |
3 | import android.os.Bundle
4 | import android.widget.EditText
5 | import com.lzh.compiler.parceler.annotation.Arg
6 | import com.lzh.compiler.parceler.annotation.BundleBuilder
7 | import com.lzh.compiler.parcelerdemo.base.BaseActivity
8 |
9 | /**
10 | * 在kotlin中使用示例
11 | * Created by haoge on 2018/4/11.
12 | */
13 | @BundleBuilder
14 | class KotlinLoginActivity : BaseActivity() {
15 |
16 | @Arg
17 | var username: String? = null
18 | @Arg
19 | var password: String? = null
20 |
21 | override fun onCreate(savedInstanceState: Bundle?) {
22 | super.onCreate(savedInstanceState)
23 | setContentView(R.layout.activity_login)
24 |
25 | findViewById(R.id.username).setText(username)
26 | findViewById(R.id.password).setText(password)
27 | }
28 |
29 | override fun onBackPressed() {
30 | setResult(2)
31 | finish()
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo;
2 |
3 | import android.os.Bundle;
4 | import android.widget.EditText;
5 |
6 | import com.lzh.compiler.parceler.annotation.Arg;
7 | import com.lzh.compiler.parceler.annotation.BundleBuilder;
8 | import com.lzh.compiler.parcelerdemo.base.BaseActivity;
9 |
10 | @BundleBuilder
11 | public class LoginActivity extends BaseActivity{
12 |
13 | @Arg("username")
14 | private String username;
15 | @Arg("password")
16 | String password;
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_login);
22 | ((EditText) findViewById(R.id.username)).setText(username);
23 | ((EditText) findViewById(R.id.password)).setText(password);
24 | }
25 |
26 | public String getUsername() {
27 | return username;
28 | }
29 |
30 | public void setUsername(String username) {
31 | this.username = username;
32 | }
33 |
34 | @Override
35 | public void onBackPressed() {
36 | setResult(1);
37 | finish();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.util.Log;
6 | import android.view.View;
7 |
8 | import com.lzh.compiler.parceler.ActivityResultCallback;
9 | import com.lzh.compiler.parceler.IBundleBuilder;
10 | import com.lzh.compiler.parceler.Parceler;
11 | import com.lzh.compiler.parceler.annotation.FastJsonConverter;
12 | import com.lzh.compiler.parcelerdemo.base.BaseActivity;
13 |
14 | import java.util.HashMap;
15 | import java.util.LinkedHashMap;
16 |
17 | public class MainActivity extends BaseActivity{
18 |
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_main);
23 | // 配置数据装换器
24 | Parceler.setDefaultConverter(FastJsonConverter.class);
25 | }
26 |
27 | /**
28 | * 到数据注入功能展示页
29 | */
30 | public void toInjectorActivity(View view) {
31 | startActivity(new Intent(this, InjectorActivity.class));
32 | }
33 |
34 | /**
35 | * 到基础Bundle存取功能展示页
36 | */
37 | public void toBundleActivity(View view) {
38 | startActivity(new Intent(this, BundleActivity.class));
39 | }
40 |
41 | public void toIntentActivity(View view) {
42 | // 根据LoginActivity所生成的BundleBuilder类。创建Builder实例。并传入数据
43 | IBundleBuilder builder = LoginActivityBundleBuilder.create(null)
44 | .setUsername("IntentLauncher tester")
45 | .setPassword("123456");
46 |
47 | // 使用IntentLauncher结合Builder进行组件启动
48 | Parceler.createLauncher(builder)
49 | .setRequestCode(1001)
50 | .start(this);
51 | }
52 |
53 | public void toTestCastActivity(View view) {
54 | Intent intent = new Intent(this, TestCastActivity.class);
55 | // 此处将会被系统序列化之后。类型会变化的数据类型实例存入Intent中进行传递。测试。
56 | HashMap map = new LinkedHashMap<>();
57 | map.put("Hello", "World");
58 | // 传递HashMap的子类,目标页取出时数据类型为 HashMap
59 | intent.putExtra("hashMap", map);
60 |
61 | // 传入StringBuilder, 目标页取出时数据类型为 String
62 | intent.putExtra("builder", (CharSequence) new StringBuilder("StringBuilder"));
63 | // 传递StringBuffer, 目标页取出时数据类型为 String
64 | intent.putExtra("buffer", (CharSequence) new StringBuffer("StringBuffer"));
65 |
66 | // 传递Parcelable的子类数组,目标页取出时数据类型为 Parcelable[]
67 | intent.putExtra("parcelables", new TestCastActivity.SubParcelable[]{new TestCastActivity.SubParcelable()});
68 |
69 | startActivity(intent);
70 | }
71 |
72 | public void toKotlinLoginActivity(View view) {
73 |
74 | IBundleBuilder builder = KotlinLoginActivityBundleBuilder.create(null)
75 | .setUsername("Kotlin")
76 | .setPassword("123455");
77 |
78 | Parceler.createLauncher(builder)
79 | .setResultCallback(new ActivityResultCallback() {
80 | @Override
81 | public void onResult(int resultCode, Intent data) {
82 | Log.e("MainActivity", "KotlinLoginResult:" + resultCode);
83 | }
84 | })
85 | .start(this);
86 | }
87 |
88 | @Override
89 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
90 | super.onActivityResult(requestCode, resultCode, data);
91 | System.err.println("requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");
92 | }
93 | }
94 |
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/TestCastActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo;
2 |
3 | import android.os.Bundle;
4 | import android.os.Parcel;
5 | import android.os.Parcelable;
6 | import android.widget.Toast;
7 |
8 | import com.lzh.compiler.parceler.annotation.Arg;
9 | import com.lzh.compiler.parcelerdemo.base.BaseActivity;
10 |
11 | import java.util.LinkedHashMap;
12 |
13 | /**
14 | * 此测试页面主要用于测试部分数据跨组件序列化传递后。传递后所读取的对象与原始数据不一致的情况,如:
15 | *
16 | * StringBuilder与StringBuffer传递后。取出为String
17 | */
18 | public class TestCastActivity extends BaseActivity {
19 |
20 | @Arg
21 | StringBuilder builder;
22 | @Arg
23 | StringBuffer buffer;
24 | @Arg
25 | SubParcelable[] parcelables;
26 | @Arg
27 | LinkedHashMap hashMap;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_test_cast);
33 | try {
34 | checkForNull(builder, "builder");
35 | checkForNull(buffer, "buffer");
36 | checkForNull(parcelables, "parcelables");
37 | checkForNull(hashMap, "hashMap");
38 | } catch (Exception e) {
39 | Toast.makeText(this, "类转换兼容测试失败。", Toast.LENGTH_SHORT).show();
40 | finish();
41 | }
42 | }
43 |
44 | void checkForNull(Object obj, String name) throws Exception{
45 | if (obj == null) {
46 | throw new RuntimeException(String.format(
47 | "检查到检查对象TestCastActivity.%s为null,数据转换兼容失败", name
48 | ));
49 | }
50 | }
51 |
52 | public static class SubParcelable implements Parcelable {
53 | public SubParcelable() {
54 | }
55 |
56 | protected SubParcelable(Parcel in) {
57 | }
58 |
59 | @Override
60 | public void writeToParcel(Parcel dest, int flags) {
61 | }
62 |
63 | @Override
64 | public int describeContents() {
65 | return 0;
66 | }
67 |
68 | public static final Creator CREATOR = new Creator() {
69 | @Override
70 | public SubParcelable createFromParcel(Parcel in) {
71 | return new SubParcelable(in);
72 | }
73 |
74 | @Override
75 | public SubParcelable[] newArray(int size) {
76 | return new SubParcelable[size];
77 | }
78 | };
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/base/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo.base;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | import com.lzh.compiler.parceler.Parceler;
8 |
9 | // 将注入器配置到基类中。一次配置,所有子类共同使用
10 | public abstract class BaseActivity extends Activity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | Parceler.toEntity(this,getIntent());
16 | }
17 |
18 | @Override
19 | public void setContentView(int layoutResID) {
20 | super.setContentView(layoutResID);
21 | }
22 |
23 | @Override
24 | protected void onSaveInstanceState(Bundle outState) {
25 | super.onSaveInstanceState(outState);
26 | Parceler.toBundle(this,outState);
27 | }
28 |
29 | @Override
30 | protected void onRestoreInstanceState(Bundle savedInstanceState) {
31 | super.onRestoreInstanceState(savedInstanceState);
32 | Parceler.toEntity(this,savedInstanceState);
33 | }
34 |
35 | @Override
36 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
37 | Parceler.dispatchActivityResult(this, requestCode, resultCode, data);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/bean/Book.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo.bean;
2 |
3 |
4 | import com.lzh.compiler.parceler.annotation.Arg;
5 | import com.lzh.compiler.parceler.annotation.NonNull;
6 |
7 | public class Book{
8 | @NonNull
9 | @Arg
10 | public String username;
11 | @Arg
12 | public float price;
13 |
14 | public Book() {
15 | }
16 |
17 | public Book(String username, float price) {
18 | this.username = username;
19 | this.price = price;
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return "Book{" +
25 | "username='" + username + '\'' +
26 | ", price=" + price +
27 | '}';
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/bean/BundleInfo.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo.bean;
2 |
3 | import android.os.Binder;
4 | import android.os.Bundle;
5 | import android.os.IBinder;
6 | import android.os.Parcelable;
7 | import android.util.SparseArray;
8 |
9 | import com.lzh.compiler.parceler.annotation.Arg;
10 |
11 | import java.io.Serializable;
12 | import java.util.ArrayList;
13 |
14 | public class BundleInfo {
15 |
16 | // ====所有bundle直接支持的数据类型。============
17 | @Arg
18 | public Bundle bundle = new Bundle();
19 | @Arg
20 | public IBinder binder = new Binder();
21 | @Arg
22 | public boolean bool = true;
23 | @Arg
24 | public Boolean UpBool = true;
25 | @Arg
26 | public boolean[] boolArr = new boolean[]{true};
27 | @Arg
28 | public byte bt = 1;
29 | @Arg
30 | public Byte UpBt = 2;
31 | @Arg
32 | public byte[] byArr = new byte[]{0, 1};
33 | @Arg
34 | public char cr = 'a';
35 | @Arg
36 | public Character UpCr = 'b';
37 | @Arg
38 | public char[] crArr = new char[]{'a'};
39 |
40 | @Arg
41 | public int it = 1;
42 | @Arg
43 | public Integer UpInt = 2;
44 | @Arg
45 | public int[] itArr = new int[]{0, 1};
46 |
47 | @Arg
48 | public long lg = 2L;
49 | @Arg
50 | public Long UpLg = 3L;
51 | @Arg
52 | public long[] lgArr = new long[]{2L};
53 |
54 | @Arg
55 | public float ft = 1.0f;
56 | @Arg
57 | public Float UpFt = 2.0f;
58 | @Arg
59 | public float[] ftArr = new float[]{0f, 1f};
60 |
61 | @Arg
62 | public double db = 1d;
63 | @Arg
64 | public Double UpDb = 2d;
65 | @Arg
66 | public double[] dbArr = new double[]{0d, 1d};
67 | @Arg
68 | public String str = "str";
69 | @Arg
70 | public String[] strArr = new String[]{"arr"};
71 | @Arg
72 | public ArrayList strList = new ArrayList<>();
73 |
74 | @Arg
75 | public StringBuilder charSequence = new StringBuilder("charSequence");
76 | @Arg
77 | public StringBuilder[] charSequencesArr = new StringBuilder[]{new StringBuilder("charSequence")};// CharSequence[]
78 | @Arg
79 | public ArrayList charSequencesList = new ArrayList<>();
80 | @Arg
81 | public Info parcelable = new Info();
82 | @Arg
83 | public Info[] parcelables = new Info[]{new Info()};// Parcelable[]
84 | @Arg
85 | public ArrayList stringArrayList = new ArrayList<>();
86 | @Arg
87 | public ArrayList parcelableArrayList = new ArrayList<>();
88 | @Arg
89 | public ArrayList integerArrayList = new ArrayList<>();
90 | @Arg
91 | public SparseArray parcelableSparseArray = new SparseArray<>();
92 |
93 | @Arg
94 | public Serializable serializable = new Info();
95 |
96 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/bean/Info.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo.bean;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * Created by admin on 16/10/14.
10 | */
11 |
12 | public class Info implements Serializable, Parcelable{
13 | public Info() {
14 | }
15 |
16 | protected Info(Parcel in) {
17 | }
18 |
19 | public static final Creator CREATOR = new Creator() {
20 | @Override
21 | public Info createFromParcel(Parcel in) {
22 | return new Info(in);
23 | }
24 |
25 | @Override
26 | public Info[] newArray(int size) {
27 | return new Info[size];
28 | }
29 | };
30 |
31 | @Override
32 | public String toString() {
33 | return "Info{}";
34 | }
35 |
36 | @Override
37 | public int describeContents() {
38 | return 0;
39 | }
40 |
41 | @Override
42 | public void writeToParcel(Parcel dest, int flags) {
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/bean/NormalUser.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo.bean;
2 |
3 | /**
4 | * @author haoge on 2018/3/30.
5 | */
6 |
7 | public class NormalUser {
8 | public String username;
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/lzh/compiler/parcelerdemo/bean/SerialUser.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parcelerdemo.bean;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * @author haoge on 2018/3/30.
7 | */
8 |
9 | public class SerialUser implements Serializable {
10 | public String username;
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_bundle.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
23 |
29 |
30 |
36 |
37 |
42 |
43 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_injector.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
23 |
24 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
24 |
25 |
32 |
33 |
39 |
40 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test_cast.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JumeiRdGroup/Parceler/331b69709e4a1709a8e73d8ac4fdb661127c9deb/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JumeiRdGroup/Parceler/331b69709e4a1709a8e73d8ac4fdb661127c9deb/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JumeiRdGroup/Parceler/331b69709e4a1709a8e73d8ac4fdb661127c9deb/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JumeiRdGroup/Parceler/331b69709e4a1709a8e73d8ac4fdb661127c9deb/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JumeiRdGroup/Parceler/331b69709e4a1709a8e73d8ac4fdb661127c9deb/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Parceler
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.2.31'
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.1.1'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | maven { url "https://jitpack.io" }
21 | google()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
--------------------------------------------------------------------------------
/compiler/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/compiler/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'maven'
3 | dependencies {
4 | implementation 'com.squareup:javapoet:1.7.0'
5 | implementation project(':annotation')
6 | }
7 | targetCompatibility = '1.7'
8 | sourceCompatibility = '1.7'
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/ParcelException.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor;
2 |
3 | import javax.lang.model.element.Element;
4 |
5 | public class ParcelException extends RuntimeException {
6 | private Element ele;
7 |
8 | @SuppressWarnings("WeakerAccess")
9 | public ParcelException(String message, Throwable cause, Element ele) {
10 | super(message, cause);
11 | this.ele = ele;
12 | }
13 |
14 | public ParcelException(String message, Element ele) {
15 | super(message);
16 | this.ele = ele;
17 | }
18 |
19 | @SuppressWarnings("WeakerAccess")
20 | public Element getEle() {
21 | return ele;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/ParcelerCompiler.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor;
2 |
3 | import com.lzh.compiler.parceler.annotation.Arg;
4 | import com.lzh.compiler.parceler.annotation.BundleBuilder;
5 | import com.lzh.compiler.parceler.processor.factory.BuilderFactory;
6 | import com.lzh.compiler.parceler.processor.model.ElementParser;
7 | import com.lzh.compiler.parceler.processor.util.UtilMgr;
8 | import com.lzh.compiler.parceler.processor.util.Utils;
9 |
10 | import java.util.HashMap;
11 | import java.util.HashSet;
12 | import java.util.Map;
13 | import java.util.Set;
14 |
15 | import javax.annotation.processing.AbstractProcessor;
16 | import javax.annotation.processing.ProcessingEnvironment;
17 | import javax.annotation.processing.RoundEnvironment;
18 | import javax.lang.model.SourceVersion;
19 | import javax.lang.model.element.Element;
20 | import javax.lang.model.element.TypeElement;
21 | import javax.tools.Diagnostic;
22 |
23 | public class ParcelerCompiler extends AbstractProcessor {
24 |
25 | @Override
26 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
27 | try {
28 | Map map = parseArgElement(roundEnv);
29 | parseBuilderElement(roundEnv, map);
30 | } catch (ParcelException e) {
31 | e.printStackTrace();
32 | error(e.getEle(),e.getMessage());
33 | return true;
34 | }
35 | return false;
36 | }
37 |
38 | private void parseBuilderElement(RoundEnvironment roundEnv, Map map) throws ParcelException {
39 | Set extends Element> elements = roundEnv.getElementsAnnotatedWith(BundleBuilder.class);
40 | TypeElement type;
41 | try {
42 | for (Element element : elements) {
43 | type = (TypeElement) element;
44 | ElementParser parser = map.get(type);
45 | new BuilderFactory(type, parser).generate();
46 | }
47 | } catch (ParcelException e) {
48 | throw e;
49 | } catch (Throwable e) {
50 | throw new RuntimeException(e);
51 | }
52 | }
53 |
54 | /**
55 | * Parse elements with {@link Arg}
56 | * @throws ParcelException throws to notify user it occurs an exception.
57 | */
58 | private Map parseArgElement(RoundEnvironment roundEnv) throws ParcelException{
59 | Map parserMap = new HashMap<>();
60 | Set extends Element> elements = roundEnv.getElementsAnnotatedWith(Arg.class);
61 | TypeElement type = null;
62 | try {
63 | // parse and get data from elements
64 | for (Element ele : elements) {
65 | type = (TypeElement) ele.getEnclosingElement();
66 | if (parserMap.containsKey(type) || !Utils.checkClassValid(type)) {
67 | continue;
68 | }
69 | // parse and put into parser map.
70 | parserMap.put(type,ElementParser.parse(type));
71 | }
72 | // generate injector class
73 | Set keys = parserMap.keySet();
74 | for (TypeElement key : keys) {
75 | parserMap.get(key).generateClass();
76 | }
77 | } catch (ParcelException e) {
78 | throw e;
79 | } catch (Throwable e) {
80 | throw new ParcelException(String.format("Parceler compiler generated java files failed: %s,%s", type, e.getMessage()),e,type);
81 | }
82 | return parserMap;
83 | }
84 |
85 | /**
86 | * compiler output method,when compiler occurs exception.should be notice here.
87 | *
88 | * @param element Element of class who has a exception when compiled
89 | * @param message The message should be noticed to user
90 | * @param args args to inflate message
91 | */
92 | private void error(Element element, String message, Object... args) {
93 | if (args.length > 0) {
94 | message = String.format(message, args);
95 | }
96 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message, element);
97 | }
98 |
99 | @Override
100 | public SourceVersion getSupportedSourceVersion() {
101 | return SourceVersion.latestSupported();
102 | }
103 |
104 | @Override
105 | public Set getSupportedAnnotationTypes() {
106 | Set set = new HashSet<>();
107 | set.add(Arg.class.getCanonicalName());
108 | set.add(BundleBuilder.class.getCanonicalName());
109 | return set;
110 | }
111 |
112 | @Override
113 | public synchronized void init(ProcessingEnvironment processingEnv) {
114 | super.init(processingEnv);
115 | UtilMgr.getMgr().init(processingEnv);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/factory/BuilderFactory.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor.factory;
2 |
3 | import com.lzh.compiler.parceler.annotation.BundleBuilder;
4 | import com.lzh.compiler.parceler.processor.model.Constants;
5 | import com.lzh.compiler.parceler.processor.model.ElementParser;
6 | import com.lzh.compiler.parceler.processor.model.FieldData;
7 | import com.lzh.compiler.parceler.processor.util.UtilMgr;
8 | import com.lzh.compiler.parceler.processor.util.Utils;
9 | import com.squareup.javapoet.ClassName;
10 | import com.squareup.javapoet.JavaFile;
11 | import com.squareup.javapoet.MethodSpec;
12 | import com.squareup.javapoet.TypeName;
13 | import com.squareup.javapoet.TypeSpec;
14 |
15 | import java.io.IOException;
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | import javax.lang.model.element.Modifier;
20 | import javax.lang.model.element.TypeElement;
21 |
22 | /**
23 | * @author haoge on 2017/12/25.
24 | */
25 | public class BuilderFactory {
26 | private TypeElement type;
27 | private List list;
28 |
29 | public BuilderFactory(TypeElement type, ElementParser parser) {
30 | this.type = type;
31 | this.list = parser == null ? new ArrayList() : parser.getFieldsList();
32 | }
33 |
34 | public void generate() throws IOException {
35 | // check if annotated by BundleBuilder
36 | if (type.getAnnotation(BundleBuilder.class) == null) {
37 | return;
38 | }
39 |
40 | // create package and class name of generating class
41 | String packName = Utils.getPackageName(type);
42 | String clzName = type.getQualifiedName().toString();
43 | clzName = Utils.isEmpty(packName) ? clzName + Constants.BUILDER_SUFFIX
44 | : clzName.substring(packName.length() + 1).replace(".","$") + Constants.BUILDER_SUFFIX;
45 |
46 | TypeName builderClassName = ClassName.bestGuess(clzName);
47 |
48 | // create BuilderClass builder.
49 | TypeSpec.Builder classBuilder = TypeSpec.classBuilder(clzName)
50 | .addSuperinterface(Constants.CLASS_IBUNDLEBUILDER)
51 | .addModifiers(Modifier.PUBLIC);
52 |
53 | // create BundleFactory field
54 | classBuilder.addField(Constants.CLASS_FACTORY, "factory", Modifier.PRIVATE);
55 |
56 | // create create method
57 | classBuilder.addMethod(MethodSpec.methodBuilder("create")
58 | .addParameter(Constants.CLASS_BUNDLE, "bundle")
59 | .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
60 | .returns(builderClassName)
61 | .addStatement("$T builder = new $T()", builderClassName, builderClassName)
62 | .addStatement("builder.factory = $T.createFactory(bundle)", Constants.CLASS_PARCELER)
63 | .addStatement("return builder")
64 | .build());
65 |
66 | // create getTarget static method
67 | classBuilder.addMethod(MethodSpec.methodBuilder("getTarget")
68 | .addModifiers(Modifier.PUBLIC)
69 | .addAnnotation(Override.class)
70 | .returns(Class.class)
71 | .addStatement("return $T.class", type)
72 | .build());
73 |
74 | // create getFactory method
75 | classBuilder.addMethod(MethodSpec.methodBuilder("getFactory")
76 | .returns(Constants.CLASS_FACTORY)
77 | .addModifiers(Modifier.PUBLIC)
78 | .addAnnotation(Override.class)
79 | .addStatement("return factory")
80 | .build());
81 |
82 | // create getBundle method
83 | classBuilder.addMethod(MethodSpec.methodBuilder("build")
84 | .addModifiers(Modifier.PUBLIC)
85 | .addAnnotation(Override.class)
86 | .returns(Constants.CLASS_BUNDLE)
87 | .addStatement("return factory.getBundle()")
88 | .build());
89 |
90 | // create setter methods
91 | for (FieldData field : list) {
92 | MethodSpec.Builder builder = MethodSpec.methodBuilder(Utils.combineMethodName(field.getKey(), "set"))
93 | .addModifiers(Modifier.PUBLIC)
94 | .returns(builderClassName)
95 | .addParameter(TypeName.get(field.getVar().asType()), field.getKey());
96 |
97 | // add javadoc
98 | builder.addJavadoc("@see $T#$N", type, field.getVar().getSimpleName());
99 |
100 | if (field.getConverter() != null) {
101 | builder.addStatement("factory.setConverter($T.class)", field.getConverter())
102 | .addStatement("factory.put($S, $L)", field.getKey(), field.getKey())
103 | .addStatement("factory.setConverter(null)");
104 | } else {
105 | builder.addStatement("factory.put($S, $L)", field.getKey(), field.getKey());
106 | }
107 |
108 | classBuilder.addMethod(builder.addStatement("return this").build());
109 |
110 | }
111 |
112 | JavaFile.Builder builder = JavaFile.builder(packName, classBuilder.build());
113 | builder.addFileComment("The class is generated by Parceler, do not modify!");
114 | JavaFile build = builder.build();
115 |
116 | build.writeTo(UtilMgr.getMgr().getFiler());
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/factory/ClassFactory.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor.factory;
2 |
3 | import com.lzh.compiler.parceler.processor.model.Constants;
4 | import com.lzh.compiler.parceler.processor.model.FieldData;
5 | import com.lzh.compiler.parceler.processor.util.UtilMgr;
6 | import com.lzh.compiler.parceler.processor.util.Utils;
7 | import com.squareup.javapoet.ClassName;
8 | import com.squareup.javapoet.JavaFile;
9 | import com.squareup.javapoet.MethodSpec;
10 | import com.squareup.javapoet.ParameterSpec;
11 | import com.squareup.javapoet.ParameterizedTypeName;
12 | import com.squareup.javapoet.TypeName;
13 | import com.squareup.javapoet.TypeSpec;
14 |
15 | import java.io.IOException;
16 | import java.lang.reflect.Type;
17 | import java.util.List;
18 |
19 | import javax.lang.model.element.Modifier;
20 | import javax.lang.model.element.TypeElement;
21 |
22 | public class ClassFactory {
23 |
24 | private List list;
25 | private TypeElement type;
26 |
27 | public ClassFactory (List list, TypeElement type) {
28 | this.list = list;
29 | this.type = type;
30 | }
31 |
32 | /**
33 | * To generate code.
34 | * @throws IOException exception
35 | */
36 | public void generateCode () throws IOException {
37 | // create package and class name of generating class
38 | String packName = Utils.getPackageName(type);
39 | String clzName = type.getQualifiedName().toString();
40 | clzName = Utils.isEmpty(packName) ? clzName + Constants.INJECTOR_SUFFIX
41 | : clzName.substring(packName.length() + 1).replace(".","$") + Constants.INJECTOR_SUFFIX;
42 |
43 | // create injector class builder.
44 | TypeName superTypeName = ParameterizedTypeName.get(Constants.CLASS_INJECTOR, ClassName.get(type));
45 | TypeSpec.Builder classBuilder = TypeSpec.classBuilder(clzName)
46 | .addModifiers(Modifier.PUBLIC)
47 | .addSuperinterface(superTypeName);
48 | // create method toEntity builder.
49 | MethodSpec.Builder toEntity = MethodSpec.methodBuilder(Constants.METHOD_TO_ENTITY)
50 | .addAnnotation(Override.class)
51 | .addModifiers(Modifier.PUBLIC)
52 | .returns(TypeName.VOID)
53 | .addParameter(ParameterSpec.builder(ClassName.get(type), "entity").build())
54 | .addParameter(ParameterSpec.builder(Constants.CLASS_BUNDLE, "bundle").build())
55 | .addStatement("Object obj = null");
56 |
57 | // create method toBundle builder.
58 | MethodSpec.Builder toBundle = MethodSpec.methodBuilder(Constants.METHOD_TO_BUNDLE)
59 | .addAnnotation(Override.class)
60 | .addModifiers(Modifier.PUBLIC)
61 | .returns(TypeName.VOID)
62 | .addParameter(ParameterSpec.builder(ClassName.get(type), "entity").build())
63 | .addParameter(ParameterSpec.builder(Constants.CLASS_BUNDLE, "bundle").build());
64 |
65 |
66 | toEntity.addStatement("$T.getParentInjectorByClass($T.class).toEntity(entity, bundle)", Constants.CLASS_PARCELER, ClassName.get(type));
67 | toEntity.addStatement("$T factory = $T.createFactory(bundle).ignoreException(true)", Constants.CLASS_FACTORY, Constants.CLASS_PARCELER);
68 | toEntity.addStatement("$T type", Type.class);
69 |
70 | toBundle.addStatement("$T.getParentInjectorByClass($T.class).toBundle(entity, bundle)", Constants.CLASS_PARCELER, ClassName.get(type));
71 | toBundle.addStatement("$T factory = $T.createFactory(bundle).ignoreException(true)", Constants.CLASS_FACTORY, Constants.CLASS_PARCELER);
72 |
73 | for (FieldData fieldData : list) {
74 | completeInjectToTarget(toEntity,fieldData);
75 | completeInjectToBundle(toBundle,fieldData);
76 | }
77 |
78 |
79 | classBuilder.addMethod(toEntity.build());
80 | classBuilder.addMethod(toBundle.build());
81 | JavaFile.Builder builder = JavaFile.builder(packName, classBuilder.build());
82 | builder.addFileComment("The class is generated by Parceler, do not modify!");
83 | JavaFile build = builder.build();
84 |
85 | build.writeTo(UtilMgr.getMgr().getFiler());
86 | }
87 |
88 | private void completeInjectToBundle(MethodSpec.Builder injectToBundle, FieldData fieldData) {
89 | if (fieldData.getConverter() != null) {
90 | injectToBundle.addStatement("factory.setConverter($T.class)", fieldData.getConverter());
91 | } else {
92 | injectToBundle.addStatement("factory.setConverter(null)");
93 | }
94 | if (Utils.isPrivate(fieldData.getVar())) {
95 | injectToBundle.addStatement("factory.put($S, entity.$N())", fieldData.getKey(), Utils.combineGetMethodName(fieldData.getVar()));
96 | } else {
97 | injectToBundle.addStatement("factory.put($S, entity.$N)", fieldData.getKey(), fieldData.getVar().getSimpleName());
98 | }
99 | }
100 |
101 | private void completeInjectToTarget(MethodSpec.Builder injectToData, FieldData fieldData) {
102 | injectToData.addStatement("type = $T.findType($S, $T.class)",
103 | Constants.CLASS_MANAGER, fieldData.getVar().getSimpleName(), ClassName.get(type));
104 | if (fieldData.getConverter() != null) {
105 | injectToData.addStatement("factory.setConverter($T.class)", fieldData.getConverter());
106 | } else {
107 | injectToData.addStatement("factory.setConverter(null)");
108 | }
109 | injectToData.beginControlFlow("if((obj = factory.get($S, type)) != null)", fieldData.getKey());
110 |
111 | if (Utils.isPrivate(fieldData.getVar())) {
112 | String setter = Utils.combineSetMethodName(fieldData.getVar());
113 | injectToData.addStatement("entity.$N(($T)$T.wrapCast(obj))", setter, TypeName.get(fieldData.getVar().asType()), Constants.CLASS_UTILS);
114 | } else {
115 | injectToData.addStatement("entity.$N = $T.wrapCast(obj)", fieldData.getVar().getSimpleName(), Constants.CLASS_UTILS);
116 | }
117 | injectToData.endControlFlow();
118 | if (fieldData.isNonNull()) {
119 | injectToData.beginControlFlow("else")
120 | .addStatement("throw new $T($S)", RuntimeException.class, "Could not be null")
121 | .endControlFlow();
122 | }
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/model/Constants.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor.model;
2 |
3 | import com.squareup.javapoet.ClassName;
4 |
5 | /**
6 | * Created by admin on 16/10/11.
7 | */
8 |
9 | public class Constants {
10 | public static final String INJECTOR_SUFFIX = "BundleInjector";
11 | public static final String BUILDER_SUFFIX = "BundleBuilder";
12 |
13 | // some class name that not include in java library
14 | // public static final String CLASS_NAME_BUNDLE = "android.os.Bundle";
15 | // public static final String CLASS_NAME_INTENT = "android.content.Intent";
16 | // public static final String CLASS_NAME_NONNULL = "android.support.annotation.NonNull";
17 | // public static final String CLASS_NAME_NULLABLE = "android.support.annotation.Nullable";
18 | // public static final String CLASS_NAME_BINDER = "android.os.IBinder";
19 |
20 | public static final ClassName CLASS_BUNDLE = ClassName.bestGuess("android.os.Bundle");
21 |
22 | public static ClassName CLASS_INJECTOR = ClassName.bestGuess("com.lzh.compiler.parceler.ParcelInjector");
23 | public static ClassName CLASS_PARCELER = ClassName.bestGuess("com.lzh.compiler.parceler.Parceler");
24 | public static ClassName CLASS_FACTORY = ClassName.bestGuess("com.lzh.compiler.parceler.BundleFactory");
25 | public static ClassName CLASS_MANAGER = ClassName.bestGuess("com.lzh.compiler.parceler.CacheManager");
26 | public static ClassName CLASS_UTILS = ClassName.bestGuess("com.lzh.compiler.parceler.Utils");
27 | public static ClassName CLASS_IBUNDLEBUILDER = ClassName.bestGuess("com.lzh.compiler.parceler.IBundleBuilder");
28 |
29 | public static final String METHOD_TO_ENTITY = "toEntity";
30 | public static final String METHOD_TO_BUNDLE = "toBundle";
31 | }
32 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/model/ElementParser.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor.model;
2 |
3 | import com.lzh.compiler.parceler.annotation.Arg;
4 | import com.lzh.compiler.parceler.annotation.Converter;
5 | import com.lzh.compiler.parceler.processor.factory.ClassFactory;
6 | import com.lzh.compiler.parceler.processor.util.Utils;
7 | import com.squareup.javapoet.ClassName;
8 | import com.squareup.javapoet.TypeName;
9 |
10 | import java.io.IOException;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | import javax.lang.model.element.Element;
15 | import javax.lang.model.element.TypeElement;
16 | import javax.lang.model.element.VariableElement;
17 | import javax.lang.model.type.MirroredTypeException;
18 |
19 | public class ElementParser {
20 | private TypeElement type;// The class who's field was annotated by @Arg
21 | private List list = new ArrayList<>();
22 | private ElementParser (TypeElement ele) {
23 | this.type = ele;
24 | }
25 |
26 | /**
27 | * Parse and check out all of fields that was annotated by {@link com.lzh.compiler.parceler.annotation.Arg}
28 | */
29 | private void parse() throws IOException {
30 | List fields = getAllFieldsWithArg(type);
31 | for (VariableElement var : fields) {
32 | FieldData fieldData = getFieldDataByVariable(var);
33 | list.add(fieldData);
34 | }
35 | }
36 |
37 | private FieldData getFieldDataByVariable(VariableElement var) {
38 | Arg arg = var.getAnnotation(Arg.class);
39 |
40 | FieldData fieldData = new FieldData(
41 | Utils.isEmpty(arg.value()) ? var.getSimpleName().toString() : arg.value(),
42 | var, getConverter(var)
43 | );
44 |
45 | fieldData.setNonNull(Utils.hasNonNullAnnotation(var));
46 |
47 | return fieldData;
48 | }
49 |
50 | private TypeName getConverter(VariableElement var) {
51 | Converter converter = var.getAnnotation(Converter.class);
52 | if (converter != null) {
53 | try {
54 | return ClassName.get(converter.value());
55 | } catch (MirroredTypeException mirroredType) {
56 | return ClassName.get(mirroredType.getTypeMirror());
57 | }
58 | }
59 | return null;
60 | }
61 |
62 | /**
63 | * get all of fields that be annotated by {@link com.lzh.compiler.parceler.annotation.Arg} on itself
64 | * @param type The class to check
65 | * @return all of field elements that be annotated by {@link com.lzh.compiler.parceler.annotation.Arg}
66 | */
67 | private List getAllFieldsWithArg(TypeElement type) {
68 | List fields = new ArrayList<>();
69 | List extends Element> enclosedElements = type.getEnclosedElements();
70 | for (Element element : enclosedElements) {
71 | if (element.getKind().isField() && element.getAnnotation(Arg.class) != null) {
72 | fields.add((VariableElement) element);
73 | }
74 | }
75 | return fields;
76 | }
77 |
78 | /**
79 | * Create an {@link ElementParser} and do parsing.
80 | * @param ele the class element to be parsed.
81 | * @return The new parser instance.
82 | * @throws IOException if it occurs an error.
83 | */
84 | public static ElementParser parse (TypeElement ele) throws IOException {
85 | ElementParser parser = new ElementParser(ele);
86 | parser.parse();
87 | return parser;
88 | }
89 |
90 | public void generateClass () throws IOException {
91 | ClassFactory clzFactory = new ClassFactory(list,type);
92 | clzFactory.generateCode();
93 | }
94 |
95 | public List getFieldsList() {
96 | return list;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/model/FieldData.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor.model;
2 |
3 | import com.squareup.javapoet.TypeName;
4 |
5 | import javax.lang.model.element.VariableElement;
6 |
7 | public class FieldData {
8 | private String key;
9 | private boolean nonNull;
10 | /**
11 | * The argument element
12 | */
13 | VariableElement var;
14 |
15 | TypeName converter;
16 |
17 | public FieldData(String key, VariableElement var, TypeName converter) {
18 | this.key = key;
19 | this.var = var;
20 | this.converter = converter;
21 | }
22 |
23 | public TypeName getConverter() {
24 | return converter;
25 | }
26 |
27 | public String getKey() {
28 | return key;
29 | }
30 |
31 | public VariableElement getVar() {
32 | return var;
33 | }
34 |
35 | public boolean isNonNull() {
36 | return nonNull;
37 | }
38 |
39 | public void setNonNull(boolean nonNull) {
40 | this.nonNull = nonNull;
41 | }
42 |
43 |
44 | @Override
45 | public String toString() {
46 | return "FieldData{" +
47 | "key='" + key + '\'' +
48 | ", nonNull=" + nonNull +
49 | ", var=" + var +
50 | '}';
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/util/UtilMgr.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor.util;
2 |
3 | import javax.annotation.processing.Filer;
4 | import javax.annotation.processing.Messager;
5 | import javax.annotation.processing.ProcessingEnvironment;
6 | import javax.lang.model.util.Elements;
7 | import javax.lang.model.util.Types;
8 |
9 | public class UtilMgr {
10 |
11 | private Elements elementUtils = null;
12 | private Filer filer = null;
13 | private Messager messager = null;
14 | private Types typeUtils = null;
15 |
16 | private static UtilMgr mgr = new UtilMgr();
17 |
18 | public void init (ProcessingEnvironment environment) {
19 | setElementUtils(environment.getElementUtils());
20 | setFiler(environment.getFiler());
21 | setMessager(environment.getMessager());
22 | setTypeUtils(environment.getTypeUtils());
23 | }
24 |
25 | private UtilMgr() {
26 | }
27 |
28 | public static UtilMgr getMgr() {
29 | return mgr;
30 | }
31 |
32 | public Elements getElementUtils() {
33 | return elementUtils;
34 | }
35 |
36 | public void setElementUtils(Elements elementUtils) {
37 | this.elementUtils = elementUtils;
38 | }
39 |
40 | public Filer getFiler() {
41 | return filer;
42 | }
43 |
44 | public void setFiler(Filer filer) {
45 | this.filer = filer;
46 | }
47 |
48 | public Messager getMessager() {
49 | return messager;
50 | }
51 |
52 | public void setMessager(Messager messager) {
53 | this.messager = messager;
54 | }
55 |
56 | public Types getTypeUtils() {
57 | return typeUtils;
58 | }
59 |
60 | public void setTypeUtils(Types typeUtils) {
61 | this.typeUtils = typeUtils;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/compiler/src/main/java/com/lzh/compiler/parceler/processor/util/Utils.java:
--------------------------------------------------------------------------------
1 | package com.lzh.compiler.parceler.processor.util;
2 |
3 | import com.lzh.compiler.parceler.processor.ParcelException;
4 | import com.squareup.javapoet.TypeName;
5 |
6 | import java.util.List;
7 | import java.util.Set;
8 |
9 | import javax.lang.model.element.AnnotationMirror;
10 | import javax.lang.model.element.Element;
11 | import javax.lang.model.element.ElementKind;
12 | import javax.lang.model.element.ExecutableElement;
13 | import javax.lang.model.element.Modifier;
14 | import javax.lang.model.element.PackageElement;
15 | import javax.lang.model.element.TypeElement;
16 | import javax.lang.model.element.VariableElement;
17 | import javax.lang.model.type.TypeMirror;
18 |
19 | public class Utils {
20 |
21 | /**
22 | * check out if the class were an effective class;
23 | *
24 | * should not be modified by private,if set,should lead to crash
25 | *
26 | * @param type A element of class
27 | * @return true if it is a effective class
28 | */
29 | public static boolean checkClassValid(TypeElement type) {
30 | Set modifiers = type.getModifiers();
31 | if (modifiers.contains(Modifier.PRIVATE)) {
32 | throw new ParcelException(String.format("class %s must not be modified by private",type.getQualifiedName()),type);
33 | }
34 |
35 | return true;
36 | }
37 |
38 | /**
39 | * combine a set-method name from field name
40 | * @param field field
41 | * @return set-method name
42 | */
43 | public static String combineSetMethodName(VariableElement field) {
44 | return combineMethodName(field.getSimpleName().toString(), "set");
45 | }
46 |
47 | /**
48 | * combine a get-method name form field name
49 | * @param field field
50 | * @return get-method name
51 | */
52 | public static String combineGetMethodName(VariableElement field) {
53 | String prefix;
54 | if (TypeName.BOOLEAN.equals(TypeName.get(field.asType()))) {
55 | prefix = "is";
56 | } else {
57 | prefix = "get";
58 | }
59 | return combineMethodName(field.getSimpleName().toString(), prefix);
60 | }
61 |
62 | public static String combineMethodName(String fieldName, String prefix) {
63 | return String.format("%s%s%s", prefix, fieldName.substring(0, 1).toUpperCase(), fieldName.substring(1));
64 | }
65 |
66 | /**
67 | * Check out if it is a empty data
68 | * @param data String
69 | * @return true if is empty
70 | */
71 | public static boolean isEmpty(CharSequence data) {
72 | return data == null || data.length() == 0;
73 | }
74 |
75 | /**
76 | * get package name from class {@code type}
77 | * @param type The element of class
78 | * @return package name
79 | */
80 | public static String getPackageName(TypeElement type) {
81 | if (type == null || type.getSimpleName().toString().length() == 0) {
82 | return "";
83 | }
84 | Element parent = type.getEnclosingElement();
85 | if (parent.getKind() == ElementKind.PACKAGE) {
86 | return ((PackageElement)parent).getQualifiedName().toString();
87 | }
88 | return getPackageName((TypeElement) parent);
89 | }
90 |
91 | /**
92 | * Check out if the field {@code var} has been annotated by {@code android.support.annotation.NonNull}
93 | * @param var field
94 | * @return true if is has annotated by NonNull
95 | */
96 | public static boolean hasNonNullAnnotation(VariableElement var) {
97 | List extends AnnotationMirror> annotationMirrors = var.getAnnotationMirrors();
98 | for (AnnotationMirror mirror : annotationMirrors) {
99 | Element annoElement = UtilMgr.getMgr().getTypeUtils().asElement(mirror.getAnnotationType());
100 | if (annoElement != null && "NonNull".equals(annoElement.getSimpleName().toString())) {
101 | return true;
102 | }
103 | }
104 | return false;
105 | }
106 |
107 | public static boolean isPrivate(VariableElement field) {
108 | return field.getModifiers().contains(Modifier.PRIVATE);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/compiler/src/main/resources/META-INF/services/javax.annotation.processing.Processor:
--------------------------------------------------------------------------------
1 | com.lzh.compiler.parceler.processor.ParcelerCompiler
--------------------------------------------------------------------------------
/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 |
13 | # When configured, Gradle will run in incubating parallel mode.
14 | # This option should only be used with decoupled projects. More details, visit
15 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
16 | # org.gradle.parallel=true
17 |
18 | #org.gradle.daemon=true
19 | #org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5007
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JumeiRdGroup/Parceler/331b69709e4a1709a8e73d8ac4fdb661127c9deb/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Apr 17 17:09:42 CST 2017
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-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/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 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/javadoc.gradle:
--------------------------------------------------------------------------------
1 | // build a jar with source files
2 | task sourcesJar(type: Jar) {
3 | from android.sourceSets.main.java.srcDirs
4 | classifier = 'sources'
5 | }
6 |
7 | task javadoc(type: Javadoc) {
8 | failOnError false
9 | source = android.sourceSets.main.java.sourceFiles
10 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
11 | classpath += configurations.compile
12 | }
13 |
14 | // build a jar with javadoc
15 | task javadocJar(type: Jar, dependsOn: javadoc) {
16 | classifier = 'javadoc'
17 | from javadoc.destinationDir
18 | }
19 |
20 | artifacts {
21 | archives sourcesJar
22 | archives javadocJar
23 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':annotation', ':api', ':compiler'
--------------------------------------------------------------------------------