├── .gitignore
├── Config.gradle
├── LICENSE
├── README.md
├── ajsoup
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── zdg
│ └── ajsoup
│ ├── AJsoupReader.java
│ ├── AJsoupReaderContext.java
│ ├── annotation
│ └── Select.java
│ ├── data
│ ├── ClassDescriptor.java
│ ├── ClassReader.java
│ ├── ConstructorDescriptor.java
│ ├── GenericArrayTypeImpl.java
│ ├── ParameterizedTypeImpl.java
│ ├── Resource.java
│ └── TypeLiteral.java
│ ├── decoder
│ ├── BaseDecoder.java
│ ├── Decoder.java
│ ├── ReflectionArrayDecoder.java
│ ├── ReflectionCollectionDecoder.java
│ ├── ReflectionDecoderFactory.java
│ ├── ReflectionMapDecoder.java
│ └── ReflectionObjectDecoder.java
│ ├── exception
│ └── AJsoupReaderException.java
│ └── kit
│ ├── AnalysisDecoder.java
│ ├── AnnotationAnalysis.java
│ └── ReflectKit.java
├── build.gradle
├── converter-ajsoup
├── .gitignore
├── build.gradle
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── zdg
│ │ │ └── converter
│ │ │ └── ajsoup
│ │ │ ├── AJSOUP.java
│ │ │ ├── AJsoupConverterFactory.java
│ │ │ ├── AJsoupRequestBodyConverter.java
│ │ │ └── AJsoupResponseBodyConverter.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── github
│ └── zdongcoding
│ └── converter
│ └── jsoup
│ └── ExampleUnitTest.java
├── demo
├── .gitignore
├── build.gradle
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── github
│ │ └── zdongcoding
│ │ └── jsoup
│ │ └── demo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── github
│ │ │ └── zdongcoding
│ │ │ └── jsoup
│ │ │ └── demo
│ │ │ ├── Api.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MediaInfoBean.java
│ │ │ ├── WebBean.java
│ │ │ └── home
│ │ │ ├── HomeBean.java
│ │ │ ├── HotTopData.java
│ │ │ ├── HotTopTabBean.java
│ │ │ ├── LatestPackBean.java
│ │ │ ├── LatestVideoBean.java
│ │ │ └── NavBean.java
│ └── res
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── github
│ └── zdongcoding
│ └── jsoup
│ └── demo
│ └── ExampleUnitTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
11 | /gred*
12 | /gradlew*
13 | gradle.properties
14 | .idea/
15 | gradle/
--------------------------------------------------------------------------------
/Config.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.jfrog.bintray'
2 | apply plugin: 'com.github.dcendents.android-maven'
3 | version = libraryVersion
4 | install {
5 | repositories.mavenInstaller {
6 | // This generates POM.xml with proper parameters
7 | pom {
8 | project {
9 | packaging 'aar'
10 | // Add your description here
11 | name libraryDescription
12 | //项目的描述 你可以多写一点
13 | url siteUrl
14 | // Set your license
15 | licenses {
16 | license {
17 | name 'The Apache Software License, Version 2.0'
18 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
19 | }
20 | }
21 | developers {
22 | developer {
23 | id developerId //填写的一些基本信息
24 | name developerName
25 | email developerEmail
26 | }
27 | }
28 | scm {
29 | connection gitUrl
30 | developerConnection gitUrl
31 | url siteUrl
32 | }
33 | }
34 | }
35 | }
36 | }
37 |
38 | if (project.hasProperty("android")) { // Android libraries
39 | task sourcesJar(type: Jar) {
40 | classifier = 'sources'
41 | from android.sourceSets.main.java.srcDirs
42 | }
43 |
44 | task javadoc(type: Javadoc) {
45 | source = android.sourceSets.main.java.srcDirs
46 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
47 | }
48 | } else { // Java libraries
49 | task sourcesJar(type: Jar, dependsOn: classes) {
50 | classifier = 'sources'
51 | from sourceSets.main.allSource
52 | }
53 | }
54 |
55 | task javadocJar(type: Jar, dependsOn: javadoc) {
56 | classifier = 'javadoc'
57 | from javadoc.destinationDir
58 | }
59 |
60 | artifacts {
61 | // archives javadocJar
62 | archives sourcesJar
63 | }
64 |
65 | // Bintray
66 | Properties properties = new Properties()
67 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
68 | group = publishedGroupId
69 | bintray {
70 | user = properties.getProperty("bintray.user")
71 | key = properties.getProperty("bintray.apikey")
72 |
73 | configurations = ['archives']
74 | pkg {
75 | repo = bintrayRepo
76 | name = bintrayName
77 | desc = libraryDescription
78 | websiteUrl = siteUrl
79 | vcsUrl = gitUrl
80 | issueTrackerUrl = issueUrl
81 | licenses = allLicenses
82 | labels = alllabels
83 | publish = true
84 | publicDownloadNumbers = true
85 | // githubReleaseNotesFile="README.md"
86 | // githubRepo = 'bintray/gradle-bintray-plugin' //Optional Github repository
87 | // githubReleaseNotesFile = 'README.md' //Optional Github readme file
88 | version {
89 | desc = libraryDescription
90 | gpg {
91 | sign = true //Determines whether to GPG sign the files. The default is false
92 | passphrase = properties.getProperty("bintray.gpg.password")
93 | //Optional. The passphrase for GPG signing'
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 zdong_coding
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AJsoup
2 |
3 | [](https://www.android.com)
4 | [](https://android-arsenal.com/api?level=14)
5 | [](https://github.com/zdongcoding)
6 |
7 | > AJsoup 模块是快速将html 转换成bean 类似gson转换
8 |
9 | > 依赖 [jsoup](https://github.com/jhy/jsoup)
10 |
11 | > **使用前提你了解jsoup并且了解[jsoup的Select](https://jsoup.org/apidocs/index.html?org/jsoup/select/Selector.html)**
12 |
13 | **Gradle**
14 | > compile 'com.github.zdongcoding:ajsoup:0.1.0'
15 |
16 | **Maven**
17 | ```
18 |
19 | com.github.zdongcoding
20 | ajsoup
21 | 0.1.0
22 | pom
23 |
24 | ```
25 |
26 | 使用方法如下:
27 | ```
28 | bean.java
29 |
30 | @Select(select = "body")
31 | public class HomeBean {
32 | @Select(select = "div > div > div.listbox")
33 | public HotTopTabBean hotTopTabBean; //热门数据
34 | @Select(select = "div#nav > ul > li[id]", attr = "id")
35 | public Map navBeans;
36 | @Select(select = "div#nav-under > ul >li:has(a)") //排除无 navUnderBeans;
38 | @Select(select = "div#body > div.left.noborder.clearfix.block1 > ul")
39 | public List latests;
40 | @Select(select = "div#header-in > div > ul#hot-words > li")
41 | public List searchbeans;
42 | }
43 | String html=....;
44 |
45 | HomeBean bean=AJsoupReader.deserialize(Jsoup.parse(html), HomeBean.class);
46 |
47 | ```
48 |
49 | # AJsoup---->Converter-Ajsoup
50 |
51 | > 使用过Retrofit 一看这个名字就知道做什么的
52 |
53 | **Gradle**
54 | > compile 'com.github.zdongcoding:converter-ajsoup:0.1.0'
55 |
56 | **Maven**
57 | ```
58 |
59 | com.github.zdongcoding
60 | converter-ajsoup
61 | 0.1.0
62 | pom
63 |
64 | ```
65 |
66 | 使用方法:
67 | ```
68 | Api.java
69 | public interface Api {
70 | @GET("{url}")
71 | Observable getPage(@Path(value = "url",encoded = true) String url);
72 | }
73 | api = new Retrofit.Builder().baseUrl(baseUri)
74 | .addConverterFactory(JsoupConverterFactory.create())
75 | .addConverterFactory(ScalarsConverterFactory.create())
76 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
77 | .build().create(Api.class);
78 |
79 | api.getPage("").subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber() {
80 | @Override
81 | public void onCompleted() {
82 | }
83 | @Override
84 | public void onError(Throwable e) {
85 | }
86 | @Override
87 | public void onNext(HomeBean homeBean) {
88 | view.setText(homeBean.toString());
89 | }
90 | });
91 |
92 |
93 | ```
94 | 选择器概要(Selector overview)
95 | * Tagname:通过标签查找元素(例如:a)
96 | * ns|tag:通过标签在命名空间查找元素,例如:fb|name查找元素
97 | * #id:通过ID查找元素,例如#logo
98 | * .class:通过类型名称查找元素,例如.masthead
99 | * [attribute]:带有属性的元素,例如[href]
100 | * [^attr]:带有名称前缀的元素,例如[^data-]查找HTML5带有数据集(dataset)属性的元素
101 | * [attr=value]:带有属性值的元素,例如[width=500]
102 | * [attr^=value],[attr$=value],[attr*=value]:包含属性且其值以value开头、结尾或包含value的元素,例* 如[href*=/path/]
103 | * [attr~=regex]:属性值满足正则表达式的元素,例如img[src~=(?i)\.(png|jpe?g)]
104 | * *:所有元素,例如*
105 | * 选择器组合方法
106 | * el#id::带有ID的元素ID,例如div#logo
107 | * el.class:带类型的元素,例如. div.masthead
108 | * el[attr]:包含属性的元素,例如a[href]
109 | * 任意组合:例如a[href].highlight
110 | * ancestor child:继承自某祖(父)元素的子元素,例如.body p查找“body”块下的p元素
111 | * parent > child:直接为父元素后代的子元素,例如: div.content > pf查找p元素,body > * 查找body元素的* 直系子元素
112 | * siblingA + siblingB:查找由同级元素A前导的同级元素,例如div.head + div
113 | * siblingA ~ siblingX:查找同级元素A前导的同级元素X例如h1 ~ p
114 | * el, el, el:多个选择器组合,查找匹配任一选择器的唯一元素,例如div.masthead, div.logo
115 | * 伪选择器(Pseudo selectors)
116 | * :lt(n):查找索引值(即DOM树中相对于其父元素的位置)小于n的同级元素,例如td:lt(3)
117 | * :gt(n):查找查找索引值大于n的同级元素,例如div p:gt(2)
118 | * :eq(n) :查找索引值等于n的同级元素,例如form input:eq(1)
119 | * :has(seletor):查找匹配选择器包含元素的元素,例如div:has(p)
120 | * :not(selector):查找不匹配选择器的元素,例如div:not(.logo)
121 | * :contains(text):查找包含给定文本的元素,大小写铭感,例如p:contains(jsoup)
122 | * :containsOwn(text):查找直接包含给定文本的元素
123 | * :matches(regex):查找其文本匹配指定的正则表达式的元素,例如div:matches((?i)login)
124 | * :matchesOwn(regex):查找其自身文本匹配指定的正则表达式的元素
125 | * 注意:上述伪选择器是0-基数的,亦即第一个元素索引值为0,第二个元素index为1等
126 |
127 | 主要用到以上字段
128 |
129 | **不需要服务器 就可以做一个快速做一个客户端**
130 |
131 | 完毕,就是这么简单
132 |
--------------------------------------------------------------------------------
/ajsoup/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /*.iml
3 | /proguard-rules.pro
4 | /libs
--------------------------------------------------------------------------------
/ajsoup/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 |
4 |
5 | android {
6 | compileSdkVersion 25
7 | buildToolsVersion '26.0.3'
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 25
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'org.jsoup:jsoup:1.11.2'
25 |
26 | }
27 | task makeJar(type: Copy) {
28 | //删除存在的
29 | delete 'build/libs/ajsoup.jar'
30 | //设置拷贝的文件
31 | from('build/intermediates/bundles/release/')
32 | //打进jar包后的文件目录
33 | into('build/libs/')
34 | //将classes.jar放入build/libs/目录下
35 | //include ,exclude参数来设置过滤
36 | //(我们只关心classes.jar这个文件)
37 | include('classes.jar')
38 | //重命名
39 | rename ('classes.jar', 'ajsoup.jar')
40 | }
41 | ext{
42 | bintrayRepo = 'maven'
43 | bintrayName = 'Ajsoup'
44 |
45 | publishedGroupId = 'com.zdg'
46 | libraryName = 'ajsoup'
47 | artifact = 'ajsoup'
48 | maturity ='Stable'
49 | libraryDescription = 'base on jsoup Automatically parsed into bean'
50 |
51 | siteUrl = 'https://github.com/zdongcoding/jsouplib'
52 | gitUrl = 'https://github.com/zdongcoding/jsouplib.git'
53 | issueUrl='https://github.com/zdongcoding/jsouplib/issues'
54 | libraryVersion = '1.0.0-beta1'
55 | alllabels = ['android','jsoup']
56 | developerId = 'zdongcoding'
57 | developerName = 'zoudong'
58 | developerEmail = 'zoudongq1990@gmail.com'
59 |
60 | licenseName = 'The Apache Software License, Version 2.0'
61 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
62 | allLicenses = ["Apache-2.0"]
63 | }
64 | //apply from: 'https://raw.githubusercontent.com/zdongcoding/bintrayhelper/master/SimpleBintray.gradle'
--------------------------------------------------------------------------------
/ajsoup/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/AJsoupReader.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup;
2 |
3 |
4 |
5 |
6 | import com.zdg.ajsoup.data.ClassDescriptor;
7 | import com.zdg.ajsoup.data.ClassReader;
8 | import com.zdg.ajsoup.data.TypeLiteral;
9 | import com.zdg.ajsoup.kit.AnalysisDecoder;
10 | import com.zdg.ajsoup.kit.AnnotationAnalysis;
11 |
12 | import org.jsoup.Jsoup;
13 | import org.jsoup.nodes.Document;
14 | import org.jsoup.select.Elements;
15 |
16 |
17 | /**
18 | * Created by zoudong on 2017/3/10.
19 | */
20 |
21 | public class AJsoupReader {
22 | public static final boolean isDebug=false;
23 | public static ThreadLocal jsp = new ThreadLocal() {
24 | @Override
25 | protected AJsoupReader initialValue() {
26 | return new AJsoupReader();
27 | }
28 | };
29 |
30 | public static final T deserialize(Document document, Class clazz) {
31 | AJsoupReader context = jsp.get();
32 | ClassDescriptor classDescriptor = ClassReader.getClassDescriptor(clazz, true);
33 |
34 | if (classDescriptor.clazz_anno == null)
35 | throw new RuntimeException(clazz + " you must used once Annotation ");
36 | Elements elements = AnnotationAnalysis.analysis(document.children(), classDescriptor.clazz_anno);
37 | T val = context.read(clazz, new AJsoupReaderContext(elements, classDescriptor.clazz_anno));
38 | return val;
39 | }
40 | public static final T deserialize(String document, Class clazz) {
41 | AJsoupReader context = jsp.get();
42 | ClassDescriptor classDescriptor = ClassReader.getClassDescriptor(clazz, true);
43 | Document parse = Jsoup.parse(document);
44 | if (classDescriptor.clazz_anno == null)
45 | throw new RuntimeException(clazz + " you must used once Annotation ");
46 | if (isDebug) System.out.println("deserialize: "+classDescriptor.clazz_anno[0].toString() );
47 | Elements elements = AnnotationAnalysis.analysis(parse.children(), classDescriptor.clazz_anno);
48 | if (isDebug) System.out.println("---->" +elements.html());
49 | T val = context.read(clazz, new AJsoupReaderContext(elements, classDescriptor.clazz_anno));
50 | return val;
51 | }
52 | @SuppressWarnings("unchecked")
53 | public final T read(Class clazz, AJsoupReaderContext iterator) {
54 | return (T) AnalysisDecoder.getDecoder(TypeLiteral.create(clazz).getDecoderCacheKey(), clazz).decode(iterator);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/AJsoupReaderContext.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup;
2 |
3 |
4 | import com.zdg.ajsoup.annotation.Select;
5 | import com.zdg.ajsoup.data.Resource;
6 | import com.zdg.ajsoup.kit.AnnotationAnalysis;
7 |
8 | import org.jsoup.helper.StringUtil;
9 | import org.jsoup.nodes.Element;
10 | import org.jsoup.select.Elements;
11 |
12 | import java.lang.annotation.Annotation;
13 | import java.lang.reflect.InvocationTargetException;
14 | import java.math.BigDecimal;
15 | import java.math.BigInteger;
16 |
17 | /**
18 | * Created by zoudong on 2017/3/10.
19 | */
20 |
21 | public class AJsoupReaderContext {
22 | public Elements elements; //数据源
23 | public Resource resource;
24 | public Annotation[] clazzans; //父级的 注解
25 |
26 | public AJsoupReaderContext(Elements elements, Resource resource) {
27 | this.elements = elements;
28 | this.resource = resource;
29 | }
30 |
31 | public AJsoupReaderContext(Elements elements, Annotation[] clazzans) {
32 | this.elements = elements;
33 | this.clazzans = clazzans;
34 | }
35 |
36 | Annotation[] getClazzans() {
37 | return resource != null && resource.annotations != null ? resource.annotations : clazzans;
38 | }
39 |
40 | Select getSelect(Annotation[] annotations) {
41 | for (Annotation annotation : annotations) {
42 | if (annotation instanceof Select) {
43 | return (Select) annotation;
44 | }
45 | }
46 | return null;
47 | }
48 |
49 | public Float readFloat() {
50 | return null;
51 | }
52 |
53 | public Double readDouble() {
54 | return null;
55 | }
56 |
57 | public Boolean readBoolean() {
58 | if (readNull()) {
59 | return false;
60 | }
61 | Annotation[] clazzans = getClazzans();
62 | // Elements elements1 = AnnotationAnalysis.analysis(elements, clazzans);
63 | Select select = getSelect(clazzans);
64 | if (select.text()) {
65 | for (Element element : elements) {
66 | return element != null && element.hasText();
67 | }
68 | }
69 | if (!StringUtil.isBlank(select.attr())) {
70 | for (Element element : elements) {
71 | return element != null && element.hasAttr(select.attr());
72 | }
73 | }
74 | for (Element element : elements) {
75 | return element != null;
76 | }
77 | return true;
78 | }
79 |
80 | public boolean readNull() {
81 | return elements == null || elements.size() == 0;
82 | }
83 |
84 | public Short readShort() {
85 | return new Short("0");
86 | }
87 |
88 | public Integer readInt() {
89 | return 0;
90 | }
91 |
92 | public Long readLong() {
93 | return 0L;
94 | }
95 |
96 | public BigDecimal readBigDecimal() {
97 | return null;
98 | }
99 |
100 | public BigInteger readBigInteger() {
101 | return null;
102 | }
103 |
104 | public String readString() {
105 | if (readNull()) return null;
106 | Annotation[] clazzans = getClazzans();
107 | // Elements elements1 = AnnotationAnalysis.analysis(elements, clazzans);
108 | Select select = getSelect(clazzans);
109 | if (select.text()) {
110 | for (Element element : elements) {
111 | if (element != null && element.hasText()) {
112 | return element.text();
113 | }
114 | }
115 | }
116 | if (!StringUtil.isBlank(select.attr())) {
117 | for (Element element : elements) {
118 | if (element != null && element.hasAttr(select.attr())) {
119 | return element.attr(select.attr());
120 | }
121 | }
122 | }
123 | return null;
124 | }
125 |
126 | public Object read() {
127 | return null;
128 | }
129 |
130 | public void deserializeChild(Resource target, Object parant) {
131 | int anno = target.annotations != null ? target.annotations.length : 0;
132 | for (int i = 0; i < anno; i++) {
133 | if (target.annotations[i] instanceof Select) {
134 | Elements select = AnnotationAnalysis.analysis(elements, target.annotations);
135 | Object deserialize = target.deserialize(select);
136 | setToBinding(parant, target, deserialize);
137 | break;
138 | }
139 | }
140 | }
141 |
142 | private void setToBinding(Object obj, Resource resource, Object slect) {
143 | if (obj == null) {
144 | return;
145 | }
146 | try {
147 | if (resource.field != null) {
148 | resource.field.set(obj, slect);
149 | } else if (resource.method != null) {
150 | resource.method.invoke(obj, slect);
151 | }
152 | } catch (InvocationTargetException e) {
153 | e.printStackTrace();
154 | } catch (IllegalAccessException e) {
155 | e.printStackTrace();
156 | }
157 |
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/annotation/Select.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.annotation;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /**
10 | * Created by user on 2017/3/8.
11 | */
12 |
13 | @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Documented
16 | public @interface Select {
17 |
18 | String select(); //没有设置 default 必填
19 | String attr() default ""; //属性
20 |
21 | String key() default ""; //map 使用的
22 | boolean text() default false; //text
23 | }
24 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/data/ClassDescriptor.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.data;
2 |
3 | import java.lang.annotation.Annotation;
4 | import java.lang.reflect.Type;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | public class ClassDescriptor {
10 |
11 | public Class clazz;
12 | public Annotation[] clazz_anno; // 类的注解
13 | public Map lookup;
14 | public ConstructorDescriptor ctor; // 构造函数
15 | public List fields;
16 | public List setters;
17 | public List getters;
18 |
19 | public List allBindings() {
20 | ArrayList resources = new ArrayList(8);
21 | resources.addAll(fields);
22 | if (setters != null) {
23 | resources.addAll(setters);
24 | }
25 | if (getters != null) {
26 | resources.addAll(getters);
27 | }
28 | if (ctor != null) {
29 | resources.addAll(ctor.parameters);
30 | }
31 | return resources;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/data/ClassReader.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.data;
2 |
3 | import com.zdg.ajsoup.exception.AJsoupReaderException;
4 | import com.zdg.ajsoup.kit.ReflectKit;
5 |
6 | import java.lang.annotation.Annotation;
7 | import java.lang.reflect.Field;
8 | import java.lang.reflect.Method;
9 | import java.lang.reflect.Modifier;
10 | import java.lang.reflect.ParameterizedType;
11 | import java.lang.reflect.Type;
12 | import java.lang.reflect.TypeVariable;
13 | import java.util.ArrayList;
14 | import java.util.HashMap;
15 | import java.util.List;
16 | import java.util.Map;
17 |
18 |
19 | public class ClassReader {
20 |
21 |
22 |
23 | /**
24 | * @param clazz
25 | * @param includingPrivate
26 | * @return
27 | */
28 | public static ClassDescriptor getClassDescriptor(Class clazz, boolean includingPrivate) {
29 |
30 | ClassDescriptor desc = new ClassDescriptor();
31 | desc.clazz_anno = clazz.getAnnotations();
32 | desc.clazz = clazz;
33 | desc.ctor = getCtor(clazz);
34 |
35 | Map lookup = collectTypeVariableLookup(clazz);
36 | desc.lookup = lookup;
37 | desc.fields = getFields(lookup, clazz, includingPrivate);
38 | desc.setters = getSetters(lookup, clazz, includingPrivate);
39 |
40 | for (Resource field : desc.fields) { //变量
41 | if (field.valueType instanceof Class) {
42 | Class valueClazz = (Class) field.valueType;
43 | if (valueClazz.isArray()) {
44 | field.valueCanReuse = false;
45 | continue;
46 | }
47 | }
48 | }
49 | deduplicate(desc);
50 | if (includingPrivate) {
51 | if (desc.ctor.ctor != null) {
52 | desc.ctor.ctor.setAccessible(true);
53 | }
54 | if (desc.ctor.staticFactory != null) {
55 | desc.ctor.staticFactory.setAccessible(true);
56 | }
57 |
58 | }
59 | for (Resource resource : desc.allBindings()) {
60 | if (resource.fromNames == null) {
61 | resource.fromNames = new String[]{resource.name};
62 | }
63 | if (resource.field != null && includingPrivate) {
64 | resource.field.setAccessible(true);
65 | }
66 | if (resource.method != null && includingPrivate) {
67 | resource.method.setAccessible(true);
68 | }
69 |
70 | }
71 | return desc;
72 | }
73 |
74 | /**
75 | * field 和 seter geter 合并字段
76 | * @param desc
77 | */
78 | private static void deduplicate(ClassDescriptor desc) {
79 | HashMap byName = new HashMap<>();
80 | for (Resource field : desc.fields) {
81 | if (!byName.containsKey(field.name)) { //排除重复 变量
82 | byName.put(field.name, field);
83 | }
84 | }
85 | for (Resource setter : desc.setters) {
86 | Resource existing = byName.get(setter.name);
87 | if (existing == null) {
88 | byName.put(setter.name, setter);
89 | continue;
90 | }
91 | if (desc.fields.remove(existing)) {
92 | continue;
93 | }
94 | }
95 | for (Resource param : desc.ctor.parameters) {
96 | Resource existing = byName.get(param.name);
97 | if (existing == null) {
98 | byName.put(param.name, param);
99 | continue;
100 | }
101 | if (desc.fields.remove(existing)) {
102 | continue;
103 | }
104 | if (desc.setters.remove(existing)) {
105 | continue;
106 | }
107 | }
108 | }
109 |
110 | /**
111 | * 获取 clazz 无参构造方法
112 | *
113 | * @param clazz
114 | * @return
115 | */
116 | private static ConstructorDescriptor getCtor(Class clazz) {
117 | ConstructorDescriptor cctor = new ConstructorDescriptor();
118 | try {
119 | cctor.ctor = clazz.getDeclaredConstructor();
120 | } catch (Exception e) {
121 | cctor.ctor = null;
122 | }
123 | return cctor;
124 | }
125 |
126 | private static List getFields(Map lookup, Class clazz, boolean includingPrivate) {
127 | ArrayList resources = new ArrayList();
128 | for (Field field : ReflectKit.getAllFields(clazz, includingPrivate)) {
129 | Annotation[] annotations = field.getAnnotations();
130 | if (annotations ==null||annotations.length==0) {//排除未注解变量
131 | continue;
132 | }
133 | if (Modifier.isStatic(field.getModifiers())) { //去掉 static 变量
134 | continue;
135 | }
136 | if (Modifier.isTransient(field.getModifiers())) {
137 | continue;
138 | }
139 | if (!includingPrivate && !Modifier.isPublic(field.getType().getModifiers())) {
140 | continue;
141 | }
142 | if (includingPrivate) {
143 | field.setAccessible(true);
144 | }
145 | Resource resource = createBindingFromField(lookup, clazz, field);
146 | resources.add(resource);
147 | }
148 | return resources;
149 | }
150 |
151 | private static Resource createBindingFromField(Map lookup, Class clazz, Field field) {
152 | try {
153 | Resource resource = new Resource(clazz, lookup, field.getGenericType());
154 | resource.fromNames = new String[]{field.getName()};
155 | resource.name = field.getName();
156 | resource.annotations = field.getAnnotations();
157 | resource.field = field;
158 | return resource;
159 | } catch (Exception e) {
160 | throw new RuntimeException("failed to onAttachView resource for field: " + field, e);
161 | }
162 | }
163 |
164 |
165 | private static List getSetters(Map lookup, Class clazz, boolean includingPrivate) {
166 | ArrayList setters = new ArrayList();
167 | for (Method method : ReflectKit.getAllMethods(clazz, includingPrivate)) {
168 | Annotation[] annotations = method.getAnnotations();
169 | if (annotations ==null||annotations.length==0) {//排除未注解变量
170 | continue;
171 | }
172 | if (Modifier.isStatic(method.getModifiers())) {
173 | continue;
174 | }
175 | String methodName = method.getName();
176 | if (methodName.length() < 4) {
177 | continue;
178 | }
179 | if (!methodName.startsWith("set")) {
180 | continue;
181 | }
182 | Type[] paramTypes = method.getGenericParameterTypes();
183 | if (paramTypes.length != 1) {
184 | continue;
185 | }
186 | if (!includingPrivate && !Modifier.isPublic(method.getParameterTypes()[0].getModifiers())) {
187 | continue;
188 | }
189 | if (includingPrivate) {
190 | method.setAccessible(true);
191 | }
192 | try {
193 | String fromName = translateSetterName(methodName);
194 | Resource resource = new Resource(clazz, lookup, paramTypes[0]);
195 | resource.fromNames = new String[]{fromName};
196 | resource.name = fromName;
197 | resource.method = method;
198 | resource.annotations = method.getAnnotations();
199 | setters.add(resource);
200 | } catch (Exception e) {
201 | throw new AJsoupReaderException("failed to onAttachView resource from setter: " + method, e);
202 | }
203 | }
204 | return setters;
205 | }
206 |
207 |
208 | private static String translateSetterName(String methodName) {
209 | if (!methodName.startsWith("set")) {
210 | return null;
211 | }
212 | String fromName = methodName.substring("set".length());
213 | char[] fromNameChars = fromName.toCharArray();
214 | fromNameChars[0] = Character.toLowerCase(fromNameChars[0]);
215 | fromName = new String(fromNameChars);
216 | return fromName;
217 | }
218 |
219 | private static Map collectTypeVariableLookup(Type type) {
220 | HashMap vars = new HashMap();
221 | if (null == type) {
222 | return vars;
223 | }
224 | if (type instanceof ParameterizedType) {
225 | ParameterizedType pType = (ParameterizedType) type;
226 | Type[] actualTypeArguments = pType.getActualTypeArguments();
227 | Class clazz = (Class) pType.getRawType();
228 | for (int i = 0; i < clazz.getTypeParameters().length; i++) {
229 | TypeVariable variable = clazz.getTypeParameters()[i];
230 | vars.put(variable.getName() + "@" + clazz.getCanonicalName(), actualTypeArguments[i]);
231 | }
232 | vars.putAll(collectTypeVariableLookup(clazz.getGenericSuperclass()));
233 | return vars;
234 | }
235 | if (type instanceof Class) {
236 | Class clazz = (Class) type;
237 | vars.putAll(collectTypeVariableLookup(clazz.getGenericSuperclass()));
238 | return vars;
239 | }
240 | throw new RuntimeException("unexpected type: " + type);
241 | }
242 |
243 |
244 | }
245 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/data/ConstructorDescriptor.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.data;
2 |
3 | import java.lang.reflect.Constructor;
4 | import java.lang.reflect.Method;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class ConstructorDescriptor {
9 | /**
10 | * set to null if use constructor
11 | * otherwise use static method
12 | */
13 | public String staticMethodName;
14 | // option 1: use constructor
15 | public Constructor ctor;
16 | // option 2: use static method
17 | public Method staticFactory;
18 | // option 3: onAttachView by extension
19 | // public Extension objectFactory;
20 |
21 | /**
22 | * the parameters to call constructor or static method
23 | */
24 | public List parameters = new ArrayList();
25 |
26 | @Override
27 | public String toString() {
28 | return "ConstructorDescriptor{" +
29 | "staticMethodName='" + staticMethodName + '\'' +
30 | ", ctor=" + ctor +
31 | ", staticFactory=" + staticFactory +
32 | ", parameters=" + parameters +
33 | '}';
34 | }
35 | }
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/data/GenericArrayTypeImpl.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.data;
2 |
3 | import java.lang.reflect.GenericArrayType;
4 | import java.lang.reflect.Type;
5 |
6 | public class GenericArrayTypeImpl implements GenericArrayType {
7 |
8 | private final Type componentType;
9 |
10 | GenericArrayTypeImpl(Type componentType) {
11 | this.componentType = componentType;
12 | }
13 |
14 | @Override
15 | public Type getGenericComponentType() {
16 | return componentType;
17 | }
18 |
19 | @Override
20 | public boolean equals(Object o) {
21 | if (this == o) return true;
22 | if (o == null || getClass() != o.getClass()) return false;
23 |
24 | GenericArrayTypeImpl that = (GenericArrayTypeImpl) o;
25 |
26 | return componentType != null ? componentType.equals(that.componentType) : that.componentType == null;
27 |
28 | }
29 |
30 | @Override
31 | public int hashCode() {
32 | return componentType != null ? componentType.hashCode() : 0;
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "GenericArrayTypeImpl{" +
38 | "componentType=" + componentType +
39 | '}';
40 | }
41 | }
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/data/ParameterizedTypeImpl.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.data;
2 |
3 | import java.lang.reflect.ParameterizedType;
4 | import java.lang.reflect.Type;
5 | import java.util.Arrays;
6 |
7 | public class ParameterizedTypeImpl implements ParameterizedType {
8 | private final Type[] actualTypeArguments;
9 | private final Type ownerType;
10 | private final Type rawType;
11 |
12 | public ParameterizedTypeImpl(Type[] actualTypeArguments, Type ownerType, Type rawType){
13 | this.actualTypeArguments = actualTypeArguments;
14 | this.ownerType = ownerType;
15 | this.rawType = rawType;
16 | }
17 |
18 | public Type[] getActualTypeArguments() {
19 | return actualTypeArguments;
20 | }
21 |
22 | public Type getOwnerType() {
23 | return ownerType;
24 | }
25 |
26 | public Type getRawType() {
27 | return rawType;
28 | }
29 |
30 | @Override
31 | public boolean equals(Object o) {
32 | if (this == o) return true;
33 | if (o == null || getClass() != o.getClass()) return false;
34 |
35 | ParameterizedTypeImpl that = (ParameterizedTypeImpl) o;
36 |
37 | // Probably incorrect - comparing Object[] arrays with Arrays.equals
38 | if (!Arrays.equals(actualTypeArguments, that.actualTypeArguments)) return false;
39 | if (ownerType != null ? !ownerType.equals(that.ownerType) : that.ownerType != null) return false;
40 | return rawType != null ? rawType.equals(that.rawType) : that.rawType == null;
41 |
42 | }
43 |
44 | @Override
45 | public int hashCode() {
46 | int result = Arrays.hashCode(actualTypeArguments);
47 | result = 31 * result + (ownerType != null ? ownerType.hashCode() : 0);
48 | result = 31 * result + (rawType != null ? rawType.hashCode() : 0);
49 | return result;
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | String rawTypeName = rawType.toString();
55 | if (rawType instanceof Class) {
56 | Class clazz = (Class) rawType;
57 | rawTypeName = clazz.getName();
58 | }
59 | return "ParameterizedTypeImpl{" +
60 | "actualTypeArguments=" + Arrays.toString(actualTypeArguments) +
61 | ", ownerType=" + ownerType +
62 | ", rawType=" + rawTypeName +
63 | '}';
64 | }
65 |
66 | public static boolean isSameClass(Type type, Class clazz) {
67 | if (type == clazz) {
68 | return true;
69 | }
70 | if (type instanceof ParameterizedType) {
71 | ParameterizedType pType = (ParameterizedType) type;
72 | return pType.getRawType() == clazz;
73 | }
74 | return false;
75 | }
76 |
77 | public static Type useImpl(Type type, Class clazz) {
78 | if (type instanceof Class) {
79 | return clazz;
80 | }
81 | if (type instanceof ParameterizedType) {
82 | ParameterizedType pType = (ParameterizedType) type;
83 | return new ParameterizedTypeImpl(pType.getActualTypeArguments(), pType.getOwnerType(), clazz);
84 | }
85 | return null;
86 | // throw new JsonException("can not change impl for: " + type);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/data/Resource.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.data;
2 |
3 |
4 | import com.zdg.ajsoup.AJsoupReaderContext;
5 | import com.zdg.ajsoup.annotation.Select;
6 | import com.zdg.ajsoup.decoder.Decoder;
7 | import com.zdg.ajsoup.exception.AJsoupReaderException;
8 |
9 | import org.jsoup.select.Elements;
10 |
11 | import java.lang.annotation.Annotation;
12 | import java.lang.reflect.Field;
13 | import java.lang.reflect.GenericArrayType;
14 | import java.lang.reflect.GenericDeclaration;
15 | import java.lang.reflect.Method;
16 | import java.lang.reflect.ParameterizedType;
17 | import java.lang.reflect.Type;
18 | import java.lang.reflect.TypeVariable;
19 | import java.util.Map;
20 |
21 | public class Resource {
22 | // input
23 | public final Class clazz;
24 | public Annotation[] annotations;
25 | public Field field;
26 | public Method method;
27 | public boolean valueCanReuse;
28 | // input/output
29 | public String name;
30 | public Type valueType;
31 | // output
32 | public String[] fromNames; // for decoder
33 | public TypeLiteral valueTypeLiteral;
34 |
35 | private Decoder decoder; //
36 | private TypeLiteral clazzTypeLiteral;
37 |
38 | public Resource(Class clazz, Map lookup, Type valueType) {
39 | this.clazz = clazz;
40 | this.valueType = substituteTypeVariables(lookup, valueType);
41 | this.clazzTypeLiteral = TypeLiteral.create(clazz);
42 | this.valueTypeLiteral = TypeLiteral.create(this.valueType);
43 | }
44 |
45 | private static Type substituteTypeVariables(Map lookup, Type type) {
46 | if (type instanceof TypeVariable) {
47 | return translateTypeVariable(lookup, (TypeVariable) type);
48 | }
49 | if (type instanceof ParameterizedType) {
50 | ParameterizedType pType = (ParameterizedType) type;
51 | Type[] args = pType.getActualTypeArguments();
52 | for (int i = 0; i < args.length; i++) {
53 | args[i] = substituteTypeVariables(lookup, args[i]);
54 | }
55 | return new ParameterizedTypeImpl(args, pType.getOwnerType(), pType.getRawType());
56 | }
57 | if (type instanceof GenericArrayType) {
58 | GenericArrayType gaType = (GenericArrayType) type;
59 | return new GenericArrayTypeImpl(substituteTypeVariables(lookup, gaType.getGenericComponentType()));
60 | }
61 | return type;
62 | }
63 |
64 | private static Type translateTypeVariable(Map lookup, TypeVariable var) {
65 | GenericDeclaration declaredBy = var.getGenericDeclaration();
66 | if (!(declaredBy instanceof Class)) {
67 | // if the is not defined by class, there is no way to get the actual type
68 | return Object.class;
69 | }
70 | Class clazz = (Class) declaredBy;
71 | Type actualType = lookup.get(var.getName() + "@" + clazz.getCanonicalName());
72 | if (actualType == null) {
73 | // should not happen
74 | return Object.class;
75 | }
76 | if (actualType instanceof TypeVariable) {
77 | // translate to another variable, try again
78 | return translateTypeVariable(lookup, (TypeVariable) actualType);
79 | }
80 | return actualType;
81 | }
82 |
83 | public T getAnnotation(Class annotationClass) {
84 | if (annotations == null) {
85 | return null;
86 | }
87 | for (Annotation annotation : annotations) {
88 | if (annotationClass.isAssignableFrom(annotation.getClass())) {
89 | return (T) annotation;
90 | }
91 | }
92 | return null;
93 | }
94 |
95 | @Override
96 | public boolean equals(Object o) {
97 | if (this == o) return true;
98 | if (o == null || getClass() != o.getClass()) return false;
99 |
100 | Resource resource = (Resource) o;
101 |
102 | if (clazz != null ? !clazz.equals(resource.clazz) : resource.clazz != null) return false;
103 | return name != null ? name.equals(resource.name) : resource.name == null;
104 | }
105 |
106 | @Override
107 | public int hashCode() {
108 | int result = clazz != null ? clazz.hashCode() : 0;
109 | result = 31 * result + (name != null ? name.hashCode() : 0);
110 | return result;
111 | }
112 |
113 | @Override
114 | public String toString() {
115 | return "Resource{" +
116 | "clazz=" + clazz +
117 | ", name='" + name + '\'' +
118 | ", valueType=" + valueType +
119 | '}';
120 | }
121 | public String decoderCacheKey() {
122 | return this.name + "@" + this.clazzTypeLiteral.getDecoderCacheKey();
123 | }
124 |
125 | public void setDecoder(Decoder decoder) {
126 | this.decoder = decoder;
127 | }
128 |
129 | public Object deserialize(AJsoupReaderContext context){
130 | if (context==null) throw new AJsoupReaderException(" not decoder");
131 | if (decoder != null) {
132 | try {
133 | return decoder.decode(context);
134 | } catch (Exception e) {
135 | e.printStackTrace();
136 | }
137 | }
138 | return null;
139 | }
140 | public Object deserialize(Elements elements){
141 | return deserialize(new AJsoupReaderContext(elements, this));
142 | }
143 | public boolean isHasDecoder() {
144 | return decoder!=null;
145 | }
146 |
147 | private Select getAnnotationIndex(int index) {
148 | if (annotations == null || annotations.length <= index) {
149 | return null;
150 | }
151 | Annotation annotation = annotations[index];
152 | return annotation instanceof Select ? (Select) annotation : null;
153 |
154 |
155 | }
156 | public String attr(int index) {
157 | Select annotationIndex = getAnnotationIndex(index);
158 | return annotationIndex!=null ? annotationIndex.attr() : null;
159 | }
160 | public String key(int index) {
161 | Select annotationIndex = getAnnotationIndex(index);
162 | return annotationIndex!=null ? annotationIndex.key() : null;
163 | }
164 | public Boolean text(int index) {
165 | Select annotationIndex = getAnnotationIndex(index);
166 | return annotationIndex != null && annotationIndex.text();
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/data/TypeLiteral.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.data;
2 |
3 |
4 | import com.zdg.ajsoup.exception.AJsoupReaderException;
5 |
6 | import java.lang.reflect.GenericArrayType;
7 | import java.lang.reflect.ParameterizedType;
8 | import java.lang.reflect.Type;
9 | import java.math.BigDecimal;
10 | import java.math.BigInteger;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | public class TypeLiteral {
15 |
16 | public enum NativeType {
17 | FLOAT,
18 | DOUBLE,
19 | BOOLEAN,
20 | BYTE,
21 | SHORT,
22 | INT,
23 | CHAR,
24 | LONG,
25 | BIG_DECIMAL,
26 | BIG_INTEGER,
27 | STRING,
28 | OBJECT,
29 | }
30 |
31 | public static Map nativeTypes = new HashMap() {{
32 | put(float.class, NativeType.FLOAT);
33 | put(Float.class, NativeType.FLOAT);
34 | put(double.class, NativeType.DOUBLE);
35 | put(Double.class, NativeType.DOUBLE);
36 | put(boolean.class, NativeType.BOOLEAN);
37 | put(Boolean.class, NativeType.BOOLEAN);
38 | put(byte.class, NativeType.BYTE);
39 | put(Byte.class, NativeType.BYTE);
40 | put(short.class, NativeType.SHORT);
41 | put(Short.class, NativeType.SHORT);
42 | put(int.class, NativeType.INT);
43 | put(Integer.class, NativeType.INT);
44 | put(char.class, NativeType.CHAR);
45 | put(Character.class, NativeType.CHAR);
46 | put(long.class, NativeType.LONG);
47 | put(Long.class, NativeType.LONG);
48 | put(BigDecimal.class, NativeType.BIG_DECIMAL);
49 | put(BigInteger.class, NativeType.BIG_INTEGER);
50 | put(String.class, NativeType.STRING);
51 | put(Object.class, NativeType.OBJECT);
52 | }};
53 |
54 | private volatile static Map typeLiteralCache = new HashMap();
55 | final Type type;
56 | final String decoderCacheKey;
57 | final NativeType nativeType;
58 |
59 | /**
60 | * Constructs a new type literal. Derives represented class from type parameter.
61 | * Clients onAttachView an empty anonymous subclass. Doing so embeds the type parameter in the
62 | * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
63 | */
64 | @SuppressWarnings("unchecked")
65 | protected TypeLiteral() {
66 | this.type = getSuperclassTypeParameter(getClass());
67 | nativeType = nativeTypes.get(this.type);
68 | decoderCacheKey = generateDecoderCacheKey(type);
69 | }
70 |
71 | public TypeLiteral(Type type, String decoderCacheKey) {
72 | this.type = type;
73 | nativeType = nativeTypes.get(this.type);
74 | this.decoderCacheKey = decoderCacheKey;
75 | }
76 |
77 | private static String generateDecoderCacheKey(Type type) {
78 | return generateCacheKey(type, "decoder.");
79 | }
80 |
81 | private static String generateCacheKey(Type type, String prefix) {
82 | StringBuilder decoderClassName = new StringBuilder(prefix);
83 | if (type instanceof Class) {
84 | Class clazz = (Class) type;
85 | if (clazz.isAnonymousClass()) {
86 | throw new AJsoupReaderException("anonymous class not supported: " + clazz);
87 | }
88 | if (clazz.isArray()) {
89 | decoderClassName.append(clazz.getCanonicalName().replace("[]", "_array"));
90 | } else {
91 | // for nested class $
92 | decoderClassName.append(clazz.getName().replace("[]", "_array"));
93 | }
94 | } else if (type instanceof ParameterizedType) {
95 | try {
96 | ParameterizedType pType = (ParameterizedType) type;
97 | Class clazz = (Class) pType.getRawType();
98 | decoderClassName.append(clazz.getCanonicalName().replace("[]", "_array"));
99 | for (int i = 0; i < pType.getActualTypeArguments().length; i++) {
100 | String typeName = formatTypeWithoutSpecialCharacter(pType.getActualTypeArguments()[i]);
101 | decoderClassName.append('_');
102 | decoderClassName.append(typeName);
103 | }
104 | } catch (Exception e) {
105 | throw new AJsoupReaderException("failed to generate cache key for: " + type, e);
106 | }
107 | } else if (type instanceof GenericArrayType) {
108 | GenericArrayType gaType = (GenericArrayType) type;
109 | Type compType = gaType.getGenericComponentType();
110 | decoderClassName.append(formatTypeWithoutSpecialCharacter(compType));
111 | decoderClassName.append("_array");
112 | } else {
113 | throw new UnsupportedOperationException("do not know how to handle: " + type);
114 | }
115 | return decoderClassName.toString().replace("$", "_");
116 | }
117 |
118 | private static String formatTypeWithoutSpecialCharacter(Type type) {
119 | if (type instanceof Class) {
120 | Class clazz = (Class) type;
121 | return clazz.getCanonicalName();
122 | }
123 | if (type instanceof ParameterizedType) {
124 | ParameterizedType pType = (ParameterizedType) type;
125 | String typeName = formatTypeWithoutSpecialCharacter(pType.getRawType());
126 | for (Type typeArg : pType.getActualTypeArguments()) {
127 | typeName += "_";
128 | typeName += formatTypeWithoutSpecialCharacter(typeArg);
129 | }
130 | return typeName;
131 | }
132 | if (type instanceof GenericArrayType) {
133 | GenericArrayType gaType = (GenericArrayType) type;
134 | return formatTypeWithoutSpecialCharacter(gaType.getGenericComponentType()) + "_array";
135 | }
136 | throw new AJsoupReaderException("unsupported type: " + type + ", of class " + type.getClass());
137 | }
138 |
139 | static Type getSuperclassTypeParameter(Class> subclass) {
140 | Type superclass = subclass.getGenericSuperclass();
141 | if (superclass instanceof Class) {
142 | throw new AJsoupReaderException("Missing type parameter.");
143 | }
144 | ParameterizedType parameterized = (ParameterizedType) superclass;
145 | return parameterized.getActualTypeArguments()[0];
146 | }
147 |
148 | public static TypeLiteral create(Type valueType) {
149 | TypeLiteral typeLiteral = typeLiteralCache.get(valueType);
150 | if (typeLiteral != null) {
151 | return typeLiteral;
152 | }
153 | return createNew(valueType);
154 | }
155 |
156 | private synchronized static TypeLiteral createNew(Type valueType) {
157 | TypeLiteral typeLiteral = typeLiteralCache.get(valueType);
158 | if (typeLiteral != null) {
159 | return typeLiteral;
160 | }
161 | HashMap copy = new HashMap(typeLiteralCache);
162 | typeLiteral = new TypeLiteral(valueType,
163 | generateDecoderCacheKey(valueType));
164 | copy.put(valueType, typeLiteral);
165 | typeLiteralCache = copy;
166 | return typeLiteral;
167 | }
168 |
169 | public Type getType() {
170 | return type;
171 | }
172 |
173 | public String getDecoderCacheKey() {
174 | return decoderCacheKey;
175 | }
176 |
177 | public NativeType getNativeType() {
178 | return nativeType;
179 | }
180 |
181 | @Override
182 | public String toString() {
183 | return "TypeLiteral{" +
184 | "type=" + type +
185 | ", decoderCacheKey='" + decoderCacheKey + '\'' +
186 | '}';
187 | }
188 | }
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/decoder/BaseDecoder.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.decoder;
2 |
3 |
4 | import com.zdg.ajsoup.data.ClassDescriptor;
5 | import com.zdg.ajsoup.kit.AnalysisDecoder;
6 |
7 | /**
8 | * Created by zoudong on 2017/3/12.
9 | */
10 |
11 | public abstract class BaseDecoder implements Decoder {
12 | protected final ClassDescriptor desc;
13 | public BaseDecoder(Class clazz) {
14 | desc = AnalysisDecoder.createDecoder(clazz,null);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/decoder/Decoder.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.decoder;
2 |
3 |
4 | import com.zdg.ajsoup.AJsoupReaderContext;
5 |
6 | public interface Decoder {
7 |
8 | Object decode(AJsoupReaderContext context) ;
9 |
10 |
11 | abstract class BooleanDecoder implements Decoder {
12 | @Override
13 | public Object decode(AJsoupReaderContext context) {
14 | return Boolean.valueOf(decodeBoolean(context));
15 | }
16 |
17 | public abstract boolean decodeBoolean(AJsoupReaderContext context) ;
18 | }
19 |
20 | abstract class ShortDecoder implements Decoder {
21 | @Override
22 | public Object decode(AJsoupReaderContext context) {
23 | return Short.valueOf(decodeShort(context));
24 | }
25 |
26 | public abstract short decodeShort(AJsoupReaderContext context) ;
27 | }
28 |
29 | abstract class IntDecoder implements Decoder {
30 | @Override
31 | public Object decode(AJsoupReaderContext context) {
32 | return Integer.valueOf(decodeInt(context));
33 | }
34 |
35 | public abstract int decodeInt(AJsoupReaderContext context) ;
36 | }
37 |
38 | abstract class LongDecoder implements Decoder {
39 | @Override
40 | public Object decode(AJsoupReaderContext context) {
41 | return Long.valueOf(decodeLong(context));
42 | }
43 |
44 | public abstract long decodeLong(AJsoupReaderContext context) ;
45 | }
46 |
47 | abstract class FloatDecoder implements Decoder {
48 | @Override
49 | public Object decode(AJsoupReaderContext context) {
50 | return Float.valueOf(decodeFloat(context));
51 | }
52 |
53 | public abstract float decodeFloat(AJsoupReaderContext context) ;
54 | }
55 |
56 | abstract class DoubleDecoder implements Decoder {
57 |
58 | @Override
59 | public Object decode(AJsoupReaderContext context) {
60 | return Double.valueOf(decodeDouble(context));
61 | }
62 |
63 | public abstract double decodeDouble(AJsoupReaderContext context) ;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/decoder/ReflectionArrayDecoder.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.decoder;
2 |
3 |
4 | import com.zdg.ajsoup.AJsoupReaderContext;
5 | import com.zdg.ajsoup.data.TypeLiteral;
6 | import com.zdg.ajsoup.kit.AnalysisDecoder;
7 |
8 | import org.jsoup.nodes.Element;
9 | import org.jsoup.select.Elements;
10 |
11 | import java.lang.reflect.Constructor;
12 |
13 | class ReflectionArrayDecoder implements Decoder {
14 |
15 | private final Class componentType;
16 | private final Decoder compTypeDecoder;
17 | private Constructor ctor;
18 |
19 | public ReflectionArrayDecoder(Class clazz) {
20 | componentType = clazz.getComponentType();
21 | try {
22 | ctor = clazz.getConstructor();
23 | } catch (NoSuchMethodException e) {
24 | e.printStackTrace();
25 | }
26 | compTypeDecoder = AnalysisDecoder.getDecoder(TypeLiteral.create(componentType).getDecoderCacheKey(), componentType);
27 | }
28 |
29 | @Override
30 | public Object decode(AJsoupReaderContext context) {
31 | Object ctor[] = new Constructor[context.elements.size()];
32 | for (int i = 0; i < context.elements.size(); i++) {
33 | Element element = context.elements.get(i);
34 | ctor[i]=compTypeDecoder.decode( new AJsoupReaderContext(new Elements(element),context.resource));
35 | }
36 | return ctor;
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/decoder/ReflectionCollectionDecoder.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.decoder;
2 |
3 |
4 | import com.zdg.ajsoup.AJsoupReaderContext;
5 | import com.zdg.ajsoup.data.TypeLiteral;
6 | import com.zdg.ajsoup.exception.AJsoupReaderException;
7 | import com.zdg.ajsoup.kit.AnalysisDecoder;
8 |
9 | import org.jsoup.nodes.Element;
10 | import org.jsoup.select.Elements;
11 |
12 | import java.lang.reflect.Constructor;
13 | import java.lang.reflect.Type;
14 | import java.util.Collection;
15 |
16 | class ReflectionCollectionDecoder implements Decoder {
17 | private final Constructor ctor;
18 | private final Decoder compTypeDecoder;
19 |
20 | public ReflectionCollectionDecoder(Class clazz, Type[] typeArgs) {
21 | try {
22 | ctor = clazz.getConstructor();
23 | } catch (NoSuchMethodException e) {
24 | throw new AJsoupReaderException(e);
25 | }
26 | // List T 的 解析器
27 | compTypeDecoder = AnalysisDecoder.getDecoder(TypeLiteral.create(typeArgs[0]).getDecoderCacheKey(), typeArgs[0]);
28 | }
29 |
30 | @Override
31 | public Object decode(AJsoupReaderContext context) {
32 | return decode_(context);
33 | }
34 |
35 | private Object decode_(AJsoupReaderContext context) {
36 | Collection col = null;
37 | try {
38 | col = (Collection) this.ctor.newInstance();
39 | for (Element element : context.elements) { // bug 当 List t 为基本类型
40 | Object decode = compTypeDecoder.decode( new AJsoupReaderContext(new Elements(element),context.resource.annotations));
41 | col.add(decode);
42 | }
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | throw new AJsoupReaderException("list decode failure");
46 | }
47 |
48 | return col;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/decoder/ReflectionDecoderFactory.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.decoder;
2 |
3 |
4 |
5 | import java.lang.annotation.Annotation;
6 | import java.lang.reflect.Type;
7 | import java.util.Collection;
8 | import java.util.Map;
9 |
10 | public class ReflectionDecoderFactory {
11 | public static Decoder create(Class clazz, Annotation[] annotations, Type... typeArgs) {
12 | if (clazz.isArray()) {
13 | return new ReflectionArrayDecoder(clazz);
14 | }
15 | if (Collection.class.isAssignableFrom(clazz)) {
16 | return new ReflectionCollectionDecoder(clazz, typeArgs);
17 | }
18 | if (Map.class.isAssignableFrom(clazz)) {
19 | return new ReflectionMapDecoder(clazz, typeArgs);
20 | }
21 | if (clazz.isEnum()) {
22 | // return new ReflectionEnumDecoder(clazz);
23 | }
24 | return new ReflectionObjectDecoder(clazz,annotations).create();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/decoder/ReflectionMapDecoder.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.decoder;
2 |
3 |
4 |
5 |
6 |
7 | import com.zdg.ajsoup.AJsoupReaderContext;
8 | import com.zdg.ajsoup.data.TypeLiteral;
9 | import com.zdg.ajsoup.exception.AJsoupReaderException;
10 | import com.zdg.ajsoup.kit.AnalysisDecoder;
11 |
12 | import org.jsoup.helper.StringUtil;
13 | import org.jsoup.nodes.Element;
14 | import org.jsoup.select.Elements;
15 |
16 | import java.lang.reflect.Constructor;
17 | import java.lang.reflect.InvocationTargetException;
18 | import java.lang.reflect.Type;
19 | import java.util.Map;
20 |
21 | class ReflectionMapDecoder implements Decoder {
22 |
23 | private final Constructor ctor;
24 | private final Decoder valueTypeDecoder;
25 |
26 | public ReflectionMapDecoder(Class clazz, Type[] typeArgs) {
27 | try {
28 | ctor = clazz.getConstructor();
29 | } catch (NoSuchMethodException e) {
30 | throw new AJsoupReaderException(e);
31 | }
32 | TypeLiteral valueTypeLiteral = TypeLiteral.create(typeArgs[1]);
33 | valueTypeDecoder = AnalysisDecoder.getDecoder(valueTypeLiteral.getDecoderCacheKey(), typeArgs[1]);
34 | }
35 |
36 | @Override
37 | public Object decode(AJsoupReaderContext context) {
38 | return decode_(context);
39 | }
40 |
41 | private Object decode_(AJsoupReaderContext context) {
42 | Map map = (Map) createMap();
43 | if (map==null||context.readNull()) {
44 | return null;
45 | }
46 | String key = context.resource.attr(0);
47 | if (StringUtil.isBlank(key)) {
48 | throw new AJsoupReaderException("请设置 attr 表示map 中的 key");
49 | }
50 | for (Element element : context.elements) {
51 | try {
52 | if (element.hasAttr(key)) {
53 | String attr = element.attr(key);
54 | Object decode = valueTypeDecoder.decode(new AJsoupReaderContext(new Elements(element), context.resource));
55 | map.put(attr, decode);
56 | }
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | }
60 | }
61 | return map;
62 | }
63 | private Object createMap(){
64 | try {
65 | return ctor.newInstance();
66 | } catch (InstantiationException e) {
67 | e.printStackTrace();
68 | } catch (IllegalAccessException e) {
69 | e.printStackTrace();
70 | } catch (InvocationTargetException e) {
71 | e.printStackTrace();
72 | }
73 | return null;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/decoder/ReflectionObjectDecoder.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.decoder;
2 |
3 |
4 | import com.zdg.ajsoup.AJsoupReaderContext;
5 | import com.zdg.ajsoup.data.ClassDescriptor;
6 | import com.zdg.ajsoup.data.Resource;
7 | import com.zdg.ajsoup.exception.AJsoupReaderException;
8 | import com.zdg.ajsoup.kit.AnalysisDecoder;
9 |
10 | import java.lang.annotation.Annotation;
11 | import java.lang.reflect.InvocationTargetException;
12 |
13 |
14 | public class ReflectionObjectDecoder {
15 |
16 | protected ClassDescriptor desc;
17 | public ReflectionObjectDecoder(Class clazz, Annotation[] annotations) {
18 | desc= AnalysisDecoder.createDecoder(clazz, annotations);
19 | if (desc==null) throw new AJsoupReaderException("AnalysisDecoder to ClassDescriptor failure");
20 | }
21 |
22 | public Decoder create() {
23 | if (desc.ctor.parameters.isEmpty()) {
24 | return new OnlyField();
25 | // if (desc.wrappers.isEmpty()) {
26 | //
27 | // } else {
28 | // return new WithSetter();
29 | // }
30 | } else {
31 | return new WithCtor();
32 | }
33 | }
34 |
35 | public class OnlyField implements Decoder {
36 |
37 | public Object decode(AJsoupReaderContext context) {
38 | return decode_(context);
39 | }
40 |
41 | private Object decode_(AJsoupReaderContext context){
42 | Object obj = createNewObject() ;
43 | if (obj==null) throw new AJsoupReaderException("construction Exception ");
44 | for (Resource field : desc.fields) {
45 | context.deserializeChild(field,obj);
46 | }
47 | for (Resource setter : desc.setters) {
48 | context.deserializeChild(setter,obj);
49 | }
50 | return obj;
51 | }
52 |
53 | }
54 |
55 | public class WithCtor implements Decoder {
56 |
57 | @Override
58 | public Object decode(AJsoupReaderContext context) {
59 | return decode_(context);
60 | }
61 |
62 | private Object decode_(AJsoupReaderContext context){
63 |
64 | return null;
65 | }
66 | }
67 |
68 | public class WithSetter implements Decoder {
69 |
70 | @Override
71 | public Object decode(AJsoupReaderContext context) {
72 | try {
73 | return decode_(context);
74 | } catch (Exception e) {
75 | throw new AJsoupReaderException(e);
76 | }
77 | }
78 |
79 | private Object decode_(AJsoupReaderContext context) {
80 | return null;
81 | }
82 | }
83 |
84 |
85 | private Object createNewObject(Object... args) {
86 | try {
87 | if (desc.ctor != null) {
88 | if (desc.ctor.staticFactory != null) {
89 | return desc.ctor.staticFactory.invoke(null, args);
90 | } else if (desc.ctor.ctor != null) {
91 | return desc.ctor.ctor.newInstance(args);
92 | }
93 | }
94 | } catch (IllegalAccessException e) {
95 | e.printStackTrace();
96 | } catch (InstantiationException e) {
97 | e.printStackTrace();
98 | } catch (InvocationTargetException e) {
99 | e.printStackTrace();
100 | }
101 | return null;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/exception/AJsoupReaderException.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.exception;
2 |
3 |
4 | /**
5 | * Created by zoudong on 2017/3/10.
6 | */
7 |
8 | public class AJsoupReaderException extends RuntimeException {
9 | public AJsoupReaderException() {
10 | }
11 |
12 | public AJsoupReaderException(String msg) {
13 | super(msg);
14 | }
15 |
16 | public AJsoupReaderException(String message, Throwable cause) {
17 | super(message, cause);
18 | }
19 |
20 | public AJsoupReaderException(Throwable cause) {
21 | super(cause);
22 | }
23 |
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/kit/AnalysisDecoder.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.kit;
2 |
3 |
4 | import com.zdg.ajsoup.AJsoupReaderContext;
5 | import com.zdg.ajsoup.data.ClassDescriptor;
6 | import com.zdg.ajsoup.data.ClassReader;
7 | import com.zdg.ajsoup.data.Resource;
8 | import com.zdg.ajsoup.decoder.Decoder;
9 | import com.zdg.ajsoup.decoder.ReflectionDecoderFactory;
10 |
11 | import java.lang.annotation.Annotation;
12 | import java.lang.reflect.ParameterizedType;
13 | import java.lang.reflect.Type;
14 | import java.math.BigDecimal;
15 | import java.math.BigInteger;
16 | import java.util.HashMap;
17 | import java.util.Map;
18 |
19 |
20 | /**
21 | * Created by zoudong on 2017/3/10.
22 | */
23 |
24 | public class AnalysisDecoder {
25 |
26 | static volatile Map decoders = new HashMap<>(); //缓存的 decoder
27 | static volatile Map registerDecoder = new HashMap<>();
28 | static volatile Map cacheClassDescriptor = new HashMap<>();
29 |
30 | public static Decoder getDecoder(String cacheKey, Type type) {
31 | Decoder decoder = getDecoder(cacheKey);
32 | if (decoder != null) {
33 | return decoder;
34 | }
35 | return gen(cacheKey, type, null);
36 | }
37 |
38 | public static Decoder getDecoder(String cacheKey, Type type, Annotation[] annotations) {
39 | Decoder decoder = getDecoder(cacheKey);
40 | if (decoder != null) {
41 | return decoder;
42 | }
43 | return gen(cacheKey, type, annotations);
44 | }
45 |
46 | public static void registerDecoder(Class clazz, Decoder decoder) {
47 | registerDecoder.put(clazz, decoder);
48 | }
49 |
50 | public static ClassDescriptor createDecoder(Class clazz) {
51 | return createDecoder(clazz, null);
52 | }
53 |
54 | /**
55 | * @param clazz
56 | * @param anns 这个class 当着 变量时的注解
57 | * @return
58 | */
59 | public static ClassDescriptor createDecoder(Class clazz, Annotation[] anns) {
60 | if (cacheClassDescriptor.get(clazz) != null) {
61 | return cacheClassDescriptor.get(clazz);
62 | }
63 | ClassDescriptor desc = ClassReader.getClassDescriptor(clazz, true);
64 | try {
65 | if (anns != null && anns.length > 0) { //变量注解负责给 class 注解
66 | System.arraycopy(anns, 0, desc.clazz_anno, 0, anns.length - 1);
67 | }
68 | for (Resource resource : desc.ctor.parameters) {
69 | if (!resource.isHasDecoder()) {
70 | resource.setDecoder(AnalysisDecoder.getDecoder(resource));
71 | }
72 | }
73 | for (Resource resource : desc.fields) {
74 | if (!resource.isHasDecoder()) {
75 | resource.setDecoder(AnalysisDecoder.getDecoder(resource));
76 | }
77 | }
78 | for (Resource resource : desc.setters) {
79 | if (!resource.isHasDecoder()) {
80 | resource.setDecoder(AnalysisDecoder.getDecoder(resource));
81 | }
82 | }
83 |
84 | if (!desc.ctor.parameters.isEmpty()) {
85 | // tempCacheKey = "temp@" + clazz.getCanonicalName();
86 | // ctorArgsCacheKey = "ctor@" + clazz.getCanonicalName();
87 | }
88 | } finally {
89 | return desc;
90 | }
91 |
92 | }
93 |
94 | /**
95 | * 创建解析器
96 | *
97 | * @param cacheKey
98 | * @param type
99 | * @param annotations
100 | * @return
101 | */
102 | private static Decoder gen(String cacheKey, Type type, Annotation[] annotations) {
103 | Decoder decoder = getDecoder(cacheKey);
104 | if (decoder != null) {
105 | return decoder;
106 | }
107 |
108 | type = ReflectKit.chooseImpl(type);
109 |
110 | Type[] typeArgs = new Type[0];
111 | Class clazz;
112 | if (type instanceof ParameterizedType) {
113 | ParameterizedType pType = (ParameterizedType) type;
114 | clazz = (Class) pType.getRawType();
115 | typeArgs = pType.getActualTypeArguments();
116 | } else {
117 | clazz = (Class) type;
118 | }
119 | decoder = NATIVE_DECODERS.get(clazz);//基本数据类型
120 | if (decoder != null) {
121 | return decoder;
122 | }
123 | decoder = registerDecoder.get(clazz); //自定义的解析器
124 | if (decoder == null) {
125 | decoder = ReflectionDecoderFactory.create(clazz, annotations, typeArgs); //注解解析器
126 | }
127 | cacheDecoder(cacheKey, decoder);
128 | return decoder;
129 | }
130 |
131 | public static Decoder getDecoder(Resource resource) {
132 | return getDecoder(resource.decoderCacheKey(), resource.valueType, resource.annotations);
133 | }
134 |
135 | private static Decoder getDecoder(String cacheKey) {
136 | return decoders.get(cacheKey);
137 | }
138 |
139 | public synchronized static void cacheDecoder(String cacheKey, Decoder decoder) {
140 | decoders.put(cacheKey, decoder);
141 | }
142 |
143 |
144 | final static Map NATIVE_DECODERS = new HashMap() {{
145 | put(float.class, new Decoder.FloatDecoder() {
146 | @Override
147 | public float decodeFloat(AJsoupReaderContext context) {
148 | return context.readFloat();
149 | }
150 | });
151 | put(Float.class, new Decoder.FloatDecoder() {
152 | @Override
153 | public float decodeFloat(AJsoupReaderContext context) {
154 | return context.readFloat();
155 | }
156 | });
157 | put(double.class, new Decoder.DoubleDecoder() {
158 | @Override
159 | public double decodeDouble(AJsoupReaderContext context) {
160 | return context.readDouble();
161 | }
162 | });
163 | put(Double.class, new Decoder.DoubleDecoder() {
164 | @Override
165 | public double decodeDouble(AJsoupReaderContext context) {
166 | return context.readDouble();
167 | }
168 | });
169 | put(boolean.class, new Decoder.BooleanDecoder() {
170 | @Override
171 | public boolean decodeBoolean(AJsoupReaderContext context) {
172 | return context.readBoolean();
173 | }
174 | });
175 | put(Boolean.class, new Decoder.BooleanDecoder() {
176 | @Override
177 | public boolean decodeBoolean(AJsoupReaderContext context) {
178 | return context.readBoolean();
179 | }
180 | });
181 | put(byte.class, new Decoder.ShortDecoder() {
182 | @Override
183 | public short decodeShort(AJsoupReaderContext context) {
184 | return context.readShort();
185 | }
186 | });
187 | put(Byte.class, new Decoder.ShortDecoder() {
188 | @Override
189 | public short decodeShort(AJsoupReaderContext context) {
190 | return context.readShort();
191 | }
192 | });
193 | put(short.class, new Decoder.ShortDecoder() {
194 | @Override
195 | public short decodeShort(AJsoupReaderContext context) {
196 | return context.readShort();
197 | }
198 | });
199 | put(Short.class, new Decoder.ShortDecoder() {
200 | @Override
201 | public short decodeShort(AJsoupReaderContext context) {
202 | return context.readShort();
203 | }
204 | });
205 | put(int.class, new Decoder.IntDecoder() {
206 | @Override
207 | public int decodeInt(AJsoupReaderContext context) {
208 | return context.readInt();
209 | }
210 | });
211 | put(Integer.class, new Decoder.IntDecoder() {
212 | @Override
213 | public int decodeInt(AJsoupReaderContext context) {
214 | return context.readInt();
215 | }
216 | });
217 | put(char.class, new Decoder() {
218 | @Override
219 | public Object decode(AJsoupReaderContext context) {
220 | return context.readInt();
221 | }
222 | });
223 | put(Character.class, new Decoder() {
224 | @Override
225 | public Object decode(AJsoupReaderContext context) {
226 | return context.readInt();
227 | }
228 | });
229 | put(long.class, new Decoder.LongDecoder() {
230 | @Override
231 | public long decodeLong(AJsoupReaderContext context) {
232 | return context.readLong();
233 | }
234 | });
235 | put(Long.class, new Decoder.LongDecoder() {
236 | @Override
237 | public long decodeLong(AJsoupReaderContext context) {
238 | return context.readLong();
239 | }
240 | });
241 | put(BigDecimal.class, new Decoder() {
242 | @Override
243 | public Object decode(AJsoupReaderContext context) {
244 | return context.readBigDecimal();
245 | }
246 | });
247 | put(BigInteger.class, new Decoder() {
248 | @Override
249 | public Object decode(AJsoupReaderContext context) {
250 | return context.readBigInteger();
251 | }
252 | });
253 | put(String.class, new Decoder() {
254 | @Override
255 | public Object decode(AJsoupReaderContext context) {
256 | return context.readString();
257 | }
258 | });
259 | put(Object.class, new Decoder() {
260 | @Override
261 | public Object decode(AJsoupReaderContext context) {
262 | return context.read();
263 | }
264 | });
265 | }};
266 |
267 |
268 | }
269 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/kit/AnnotationAnalysis.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.kit;
2 |
3 |
4 |
5 |
6 | import com.zdg.ajsoup.annotation.Select;
7 |
8 | import org.jsoup.helper.StringUtil;
9 | import org.jsoup.select.Elements;
10 |
11 | import java.lang.annotation.Annotation;
12 |
13 | /**
14 | * Created by zoudong on 2017/3/12.
15 | */
16 |
17 | public class AnnotationAnalysis {
18 |
19 | public static Elements analysis(Elements els,Annotation[] ans){
20 | for (Annotation an : ans) {
21 | els = select(els, an);
22 | }
23 | return els;
24 | }
25 |
26 | private static Elements select(Elements els, Annotation an) {
27 | if (an instanceof Select) {
28 | try {
29 | String select = ((Select) an).select();
30 | if (!StringUtil.isBlank(select)) {
31 | els = els.select(select.trim());
32 | }
33 |
34 | } catch (Exception e) {
35 | e.printStackTrace();
36 | }
37 | }
38 | return els;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/ajsoup/src/main/java/com/zdg/ajsoup/kit/ReflectKit.java:
--------------------------------------------------------------------------------
1 | package com.zdg.ajsoup.kit;
2 |
3 | import com.zdg.ajsoup.data.ParameterizedTypeImpl;
4 |
5 | import java.lang.reflect.Field;
6 | import java.lang.reflect.Method;
7 | import java.lang.reflect.ParameterizedType;
8 | import java.lang.reflect.Type;
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.Collection;
12 | import java.util.HashMap;
13 | import java.util.HashSet;
14 | import java.util.List;
15 | import java.util.Map;
16 | import java.util.Set;
17 |
18 | /**
19 | * Created by zoudong on 2017/5/24.
20 | */
21 |
22 | public class ReflectKit {
23 |
24 | /**
25 | * 获取所有变量
26 | * @param clazz
27 | * @param includingPrivate
28 | * @return
29 | */
30 | public static List getAllFields(Class clazz, boolean includingPrivate) {
31 | List temp = Arrays.asList(clazz.getFields());
32 | List allFields = new ArrayList<>();
33 | for (Field field : temp) {
34 | if (!isContain(allFields,field)) {
35 | allFields.add(field);
36 | }
37 | }
38 | if (includingPrivate) {
39 | allFields = new ArrayList<>();
40 | Class current = clazz;
41 | while (current != null) {
42 | List fields = Arrays.asList(current.getDeclaredFields());
43 | for (Field field : fields) {
44 | if (!isContain(allFields,field)) {
45 | allFields.add(field);
46 | }
47 | }
48 | current = current.getSuperclass();
49 | }
50 | }
51 | return allFields;
52 | }
53 | /**检测Field List中是否已经包含了目标field
54 | * @param fieldList
55 | * @param field 带检测field
56 | * @return
57 | */
58 | public static boolean isContain(List fieldList,Field field){
59 | for(Field temp:fieldList){
60 | if(temp.getName().equals(field.getName())){
61 | return true;
62 | }
63 | }
64 | return false;
65 | }
66 | /**
67 | * 获取 所有的 方法
68 | * @param clazz
69 | * @param includingPrivate
70 | * @return
71 | */
72 | public static List getAllMethods(Class clazz, boolean includingPrivate) {
73 | List allMethods = Arrays.asList(clazz.getMethods());
74 | if (includingPrivate) {
75 | allMethods = new ArrayList();
76 | Class current = clazz;
77 | while (current != null) {
78 | allMethods.addAll(Arrays.asList(current.getDeclaredMethods()));
79 | current = current.getSuperclass();
80 | }
81 | }
82 | return allMethods;
83 | }
84 | public static Type chooseImpl(Type type) {
85 | Type[] typeArgs = new Type[0];
86 | Class clazz;
87 | if (type instanceof ParameterizedType) {
88 | ParameterizedType pType = (ParameterizedType) type;
89 | clazz = (Class) pType.getRawType();
90 | typeArgs = pType.getActualTypeArguments();
91 | } else {
92 | clazz = (Class) type;
93 | }
94 | if (Collection.class.isAssignableFrom(clazz)) {
95 | Type compType = Object.class;
96 | if (typeArgs.length == 0) {
97 | // default to List