Skip to content

Commit 6dfdc79

Browse files
committed
feat: enhance FastProto with annotation processor.
1 parent 5dcbf34 commit 6dfdc79

304 files changed

Lines changed: 1548 additions & 293 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ hs_err_pid*
2424

2525
# IDE Files
2626
.idea/
27-
/target
28-
fastproto.iml
27+
*.iml
28+
29+
# Maven build output
30+
target/
2931

3032
# Development notes
3133
dev_note.md

CHANGELOG-zh.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,51 @@
22

33
本文件用于记录本项目的所有重要变更。
44

5+
## [4.0.0] - 2026-01-26
6+
### 重大变更
7+
- **多模块重构**:项目拆分为两个模块:
8+
- `fastproto` - 核心库,包含所有运行时功能(artifactId 保持向后兼容)
9+
- `fastproto-processor` - 注解处理器,用于编译时公式类生成
10+
- 动态 lambda 编译默认禁用,以提升 Android/JRE 兼容性
11+
12+
### 新增
13+
- `fastproto-processor` 模块,支持 SPI 自动发现注解处理器
14+
- `FormulaProcessor` - 在编译时为 `@DecodingFormula(lambda="...")``@EncodingFormula(lambda="...")` 生成 `Function` 实现类
15+
- `CodecProcessor` - 为 `@GenerateCodec` 注解的类生成编解码包装器
16+
- `FormulaRegistry` - 运行时查找编译时生成的公式类
17+
- 通过注解处理器实现完整的 Android 和 Java 11+ JRE 兼容性
18+
19+
### 变更
20+
- Lambda 公式现在使用编译时代码生成,而非运行时动态编译
21+
- 使用 lambda 公式功能需要添加 `fastproto-processor` 依赖
22+
- 更新文档以反映新的多模块结构
23+
24+
### 升级指南
25+
从 3.x 升级的用户:
26+
27+
**Maven:**
28+
```xml
29+
<dependency>
30+
<groupId>org.indunet</groupId>
31+
<artifactId>fastproto</artifactId>
32+
<version>4.0.0</version>
33+
</dependency>
34+
<!-- 使用 lambda 公式时添加 -->
35+
<dependency>
36+
<groupId>org.indunet</groupId>
37+
<artifactId>fastproto-processor</artifactId>
38+
<version>4.0.0</version>
39+
<scope>provided</scope>
40+
</dependency>
41+
```
42+
43+
**Gradle:**
44+
```groovy
45+
implementation 'org.indunet:fastproto:4.0.0'
46+
// 使用 lambda 公式时添加
47+
annotationProcessor 'org.indunet:fastproto-processor:4.0.0'
48+
```
49+
550
## [3.12.3] - 2025-11-23
651
### 新增
752
- 新增 `@BcdType` 注解与 `BcdCodec`,支持定长 packed BCD 整数(支持大小端),映射到 `int` / `Integer` 类型。

CHANGELOG.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,51 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [4.0.0] - 2026-01-26
6+
### Breaking Changes
7+
- **Multi-module restructure**: Project split into two modules:
8+
- `fastproto` - Core library with all runtime functionality (backwards compatible artifactId)
9+
- `fastproto-processor` - Annotation processor for compile-time formula generation
10+
- Dynamic lambda compilation is now disabled by default for better Android/JRE compatibility
11+
12+
### Added
13+
- `fastproto-processor` module with SPI auto-discovery for annotation processors
14+
- `FormulaProcessor` - Generates `Function` classes at compile time for `@DecodingFormula(lambda="...")` and `@EncodingFormula(lambda="...")`
15+
- `CodecProcessor` - Generates codec wrapper classes for `@GenerateCodec` annotated classes
16+
- `FormulaRegistry` - Runtime lookup for compile-time generated formula classes
17+
- Full Android and Java 11+ JRE compatibility for lambda formulas via annotation processor
18+
19+
### Changed
20+
- Lambda formulas now use compile-time code generation instead of runtime dynamic compilation
21+
- Users need to add `fastproto-processor` as a dependency to use lambda formula features
22+
- Updated documentation for new multi-module structure
23+
24+
### Migration Guide
25+
For users upgrading from 3.x:
26+
27+
**Maven:**
28+
```xml
29+
<dependency>
30+
<groupId>org.indunet</groupId>
31+
<artifactId>fastproto</artifactId>
32+
<version>4.0.0</version>
33+
</dependency>
34+
<!-- Add if using lambda formulas -->
35+
<dependency>
36+
<groupId>org.indunet</groupId>
37+
<artifactId>fastproto-processor</artifactId>
38+
<version>4.0.0</version>
39+
<scope>provided</scope>
40+
</dependency>
41+
```
42+
43+
**Gradle:**
44+
```groovy
45+
implementation 'org.indunet:fastproto:4.0.0'
46+
// Add if using lambda formulas
47+
annotationProcessor 'org.indunet:fastproto-processor:4.0.0'
48+
```
49+
550
## [3.12.3] - 2025-11-23
651
### Added
752
- New `@BcdType` annotation and `BcdCodec` for fixed-length packed BCD integers (with byte order support), mapped to `int` / `Integer`.

README-zh.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,16 @@ FastProto 是一个面向 **二进制通信协议** 的高性能序列化 / 反
4545
<dependency>
4646
<groupId>org.indunet</groupId>
4747
<artifactId>fastproto</artifactId>
48-
<version>3.12.3</version>
48+
<version>4.0.0</version>
4949
</dependency>
50-
```
51-
52-
* Gradle
5350

54-
```gradle
55-
implementation "org.indunet:fastproto:3.12.3"
51+
<!-- 可选:使用 lambda 公式时需要 (@DecodingFormula(lambda="...")) -->
52+
<dependency>
53+
<groupId>org.indunet</groupId>
54+
<artifactId>fastproto-processor</artifactId>
55+
<version>4.0.0</version>
56+
<scope>provided</scope>
57+
</dependency>
5658
```
5759

5860
## *1. 快速入门*
@@ -168,6 +170,8 @@ public class Weather {
168170
}
169171
```
170172

173+
> **注意:** Lambda 公式需要 `fastproto-processor` 模块,请将其添加为 `provided` 作用域的依赖。详见 [Android 指南](docs/android.md)
174+
171175

172176
## *2. 注解*
173177

@@ -267,6 +271,17 @@ public class Weather {
267271

268272
* *Lambda表达式*
269273

274+
Lambda 公式由 FastProto 注解处理器(`fastproto-processor`)在编译时处理,这确保了与 Android 和 Java 11+ JRE 环境的兼容性。只需添加处理器依赖:
275+
276+
```xml
277+
<dependency>
278+
<groupId>org.indunet</groupId>
279+
<artifactId>fastproto-processor</artifactId>
280+
<version>4.0.0</version>
281+
<scope>provided</scope>
282+
</dependency>
283+
```
284+
270285
```java
271286
import org.indunet.fastproto.annotation.DecodingFormula;
272287
import org.indunet.fastproto.annotation.EncodingFormula;

README.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,16 @@ See the [CHANGELOG](CHANGELOG.md) for recent updates.
4646
<dependency>
4747
<groupId>org.indunet</groupId>
4848
<artifactId>fastproto</artifactId>
49-
<version>3.12.3</version>
49+
<version>4.0.0</version>
5050
</dependency>
51-
```
52-
53-
* Gradle
5451

55-
```gradle
56-
implementation "org.indunet:fastproto:3.12.3"
52+
<!-- Optional: For lambda formula support (@DecodingFormula(lambda="...")) -->
53+
<dependency>
54+
<groupId>org.indunet</groupId>
55+
<artifactId>fastproto-processor</artifactId>
56+
<version>4.0.0</version>
57+
<scope>provided</scope>
58+
</dependency>
5759
```
5860

5961

@@ -169,6 +171,8 @@ public class Weather {
169171
}
170172
```
171173

174+
> **Note:** Lambda formulas require the `fastproto-processor` module. Add it as a `provided` scope dependency. See [Android guide](docs/android.md) for details.
175+
172176

173177
## *2. Annotations*
174178

@@ -272,6 +276,17 @@ complex formula, it is recommended to customize formula classes by implementing
272276

273277
* *Lambda Expression*
274278

279+
Lambda formulas are processed at compile time by the FastProto annotation processor (`fastproto-processor`). This ensures compatibility with Android and Java 11+ JRE environments. Simply add the processor dependency:
280+
281+
```xml
282+
<dependency>
283+
<groupId>org.indunet</groupId>
284+
<artifactId>fastproto-processor</artifactId>
285+
<version>4.0.0</version>
286+
<scope>provided</scope>
287+
</dependency>
288+
```
289+
275290
```java
276291
import org.indunet.fastproto.annotation.DecodingFormula;
277292
import org.indunet.fastproto.annotation.EncodingFormula;

docs/android.md

Lines changed: 92 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,122 @@
11
## Android Compatibility Guide
22

3-
This page summarizes how to use FastProto on Android and current limitations.
3+
This page summarizes how to use FastProto on Android.
44

55
## What Works
66

77
- Annotation-based mapping for primitive types, arrays, strings, enums, bit/byte order, and checksum/CRC
88
- Decode/encode via `FastProto.decode(...)` and `FastProto.encode(...)`
99
- Builder/Utils APIs (no annotations)
10+
- **Lambda formulas with annotation processor** (since 4.0.0)
11+
12+
## Lambda Formulas on Android
13+
14+
Since version 4.0.0, FastProto provides a separate annotation processor module (`fastproto-processor`) that generates formula classes at compile time. This makes `@DecodingFormula(lambda = "...")` and `@EncodingFormula(lambda = "...")` fully compatible with Android.
15+
16+
### Setup
17+
18+
**Gradle (Kotlin DSL)**:
19+
```kotlin
20+
dependencies {
21+
implementation("org.indunet:fastproto:4.0.0")
22+
annotationProcessor("org.indunet:fastproto-processor:4.0.0")
23+
}
24+
25+
// For Kotlin projects, use kapt instead:
26+
// kapt("org.indunet:fastproto-processor:4.0.0")
27+
```
28+
29+
**Gradle (Groovy DSL)**:
30+
```groovy
31+
dependencies {
32+
implementation 'org.indunet:fastproto:4.0.0'
33+
annotationProcessor 'org.indunet:fastproto-processor:4.0.0'
34+
}
35+
```
36+
37+
**Maven**:
38+
```xml
39+
<dependencies>
40+
<dependency>
41+
<groupId>org.indunet</groupId>
42+
<artifactId>fastproto</artifactId>
43+
<version>4.0.0</version>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.indunet</groupId>
47+
<artifactId>fastproto-processor</artifactId>
48+
<version>4.0.0</version>
49+
<scope>provided</scope>
50+
</dependency>
51+
</dependencies>
52+
```
53+
54+
### How It Works
55+
56+
The annotation processor scans your code at compile time and generates `Function` implementation classes for each lambda expression. These generated classes are included in your APK and used at runtime instead of dynamic compilation.
57+
58+
For example, this annotation:
59+
```java
60+
@Int16Type(offset = 0)
61+
@DecodingFormula(lambda = "x -> x * 0.1")
62+
private double temperature;
63+
```
64+
65+
Generates a class like:
66+
```java
67+
public class YourClass_temperature_DecodingFormula implements Function<Integer, Object> {
68+
@Override
69+
public Object apply(Integer x) {
70+
return x * 0.1;
71+
}
72+
}
73+
```
74+
75+
### Alternative: Custom Function Classes
76+
77+
You can also use custom function classes directly without relying on the annotation processor:
78+
79+
```java
80+
public class TemperatureFormula implements Function<Integer, Double> {
81+
@Override
82+
public Double apply(Integer value) {
83+
return value * 0.1;
84+
}
85+
}
86+
87+
public class SensorData {
88+
@Int16Type(offset = 0)
89+
@DecodingFormula(TemperatureFormula.class)
90+
private double temperature;
91+
}
92+
```
1093

1194
## Current Limitations
1295

13-
- Dynamic formula compilation is unavailable on Android
14-
- Reason: Android runtime does not ship `javax.tools.JavaCompiler`, nor support loading JVM `.class` via `URLClassLoader`/`defineClass`. Only DEX is supported at runtime.
15-
- Impact: Using string-based lambda in `@DecodingFormula(lambda = "...")` / `@EncodingFormula(lambda = "...")` will fail on Android.
1696
- `java.sql.Timestamp` is not part of Android standard APIs
1797
- Impact: Types/codec relying on `java.sql.*` will not work. Prefer `long` epoch millis or `java.time.*` (with desugaring) instead.
1898

19-
## How to Use on Android
99+
## Other Android Setup
20100

21-
- Formulas
22-
- Do NOT use string-based lambdas in annotations.
23-
- Instead, implement `java.util.function.Function` (or a typed interface) as a normal class and reference the class in annotations.
24-
- Time Types
101+
- **Time Types**
25102
- Prefer `long` (epoch millis) or `java.time.Instant/LocalDateTime`.
26103
- Enable core library desugaring to use `java.time.*` on older Android.
27-
- Gradle Setup (library/app module)
104+
- **Gradle Setup (library/app module)**
28105
- compileOptions.sourceCompatibility/targetCompatibility = 1.8
29106
- coreLibraryDesugaringEnabled = true
30107
- Add dependency: `com.android.tools:desugar_jdk_libs`
31-
- R8/ProGuard
108+
- **R8/ProGuard**
32109
- Keep runtime annotations and members used by reflection
33110
- Example rules:
34111

35112
```pro
36113
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations, Signature, InnerClasses, EnclosingMethod
37114
-keep class org.indunet.fastproto.annotation.** { *; }
38-
# If you include the core jar and want to silence unused tools warnings:
39-
-dontwarn javax.tools.**
40-
-dontwarn java.net.URLClassLoader
115+
-keep class org.indunet.fastproto.formula.generated.** { *; }
41116
```
42117

43-
## Known Issues and Roadmap
44-
45-
- Dynamic compiler will be made optional/disabled on Android to avoid `javax.tools` and custom classloader usage
46-
- Provide time codecs that do not depend on `java.sql.Timestamp` (prefer `Instant/long`)
47-
- Consider publishing an Android-friendly artifact variant
48-
49-
These improvements are planned for future releases.
50-
51118
## FAQ
52119

53-
- Can I still transform values? Yes. Implement a class-based function and refer to it in annotations, or transform in your own code before/after FastProto.
54-
- Do I need ProGuard rules? If you rely on reflection/annotations, keep them as shown above. If you do not use dynamic compilation, shrinkers will strip those classes automatically.
120+
- **Can I use lambda formulas on Android?** Yes! Since 4.0.0, the `fastproto-processor` module generates formula classes at compile time, making lambda formulas fully compatible with Android.
121+
- **Do I need the annotation processor?** If you use `@DecodingFormula(lambda = "...")` or `@EncodingFormula(lambda = "...")`, yes. If you only use class-based formulas like `@DecodingFormula(MyFormula.class)`, the annotation processor is optional.
122+
- **Do I need ProGuard rules?** If you rely on reflection/annotations, keep them as shown above. The generated formula classes should also be kept.

docs/formulas.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Formulas let you convert between raw on‑wire values and engineering values. Yo
99
- Decode formula: raw -> target field type
1010
- Encode formula: target field type -> raw
1111

12-
> Android note: avoid string-based lambdas in annotations; use class-based `Function` implementations instead. See `docs/android.md`.
12+
> **Note:** Lambda formulas require the `fastproto-processor` module for compile-time code generation. This ensures compatibility with Android and Java 11+ JRE environments. See [Android guide](android.md) for setup details.
1313
1414
## Quick Steps
1515

@@ -28,10 +28,21 @@ Formulas let you convert between raw on‑wire values and engineering values. Yo
2828
- Example: reverse the above conversion.
2929

3030
### Lambda vs Class
31-
- Lambda: `@DecodingFormula(lambda = "...")` / `@EncodingFormula(lambda = "...")`
31+
- Lambda: `@DecodingFormula(lambda = "...")` / `@EncodingFormula(lambda = "...")` — requires `fastproto-processor` dependency
3232
- Class: `@DecodingFormula(MyFunc.class)` / `@EncodingFormula(MyFunc.class)` where class implements `Function<In, Out>`
3333
- Precedence: Class‑based formulas win if both lambda and class are present.
3434

35+
### Lambda Processor Setup
36+
To use lambda expressions, add the annotation processor:
37+
```xml
38+
<dependency>
39+
<groupId>org.indunet</groupId>
40+
<artifactId>fastproto-processor</artifactId>
41+
<version>4.0.0</version>
42+
<scope>provided</scope>
43+
</dependency>
44+
```
45+
3546
### Lifecycle & Errors
3647
- Formulas are compiled/bound during graph resolve and invoked per field during decode/encode.
3748
- Throwing exceptions inside formulas will surface as `DecodingException` / `EncodingException` at call sites.

0 commit comments

Comments
 (0)