代码生成开发工具【免费下载链接】autoA collection of source code generators for Java.项目地址https://gitcode.com/gh_mirrors/auto/auto点击查看免费下载SerializableAutoValueExtension是 Google Auto 项目中为AutoValue打造的序列化扩展当你的值对象包含Optional、ImmutableList等本身不可序列化的属性时它能在编译期自动生成代理对象让整个类恢复可序列化能力。本文以 serializable 扩展的官方文档 为主体结合 processor 源码 与内置序列化器的实现细节讲透它的使用方法、代理生成原理以及如何通过SerializerExtension为自定义类型扩展序列化支持。一、要解决的问题1.1 不可序列化属性的“传染性”Java 原生序列化java.io.Serializable是“自底向上”的一个类要可序列化它引用的每一个对象图成员也必须是可序列化的。这对 AutoValue 值对象提出了挑战——很多常见类型天然不可序列化java.util.OptionalJDK 明确没有实现Serializablecom.google.common.collect.ImmutableList/ImmutableMap虽然内容通常很简单但集合本身并未实现Serializable各种业务自定义类可能因为持有不可序列化字段或未实现接口而不可序列化。一旦AutoValue类的某个抽象属性类型不可序列化整个类就“被传染”即使它声明了implements Serializable也会在运行时抛出NotSerializableException。1.2 SerializableAutoValueExtension 的思路SerializableAutoValueExtension的解决方案是“代理序列化”在编译期生成一个额外的子类与一个嵌套的代理类Proxy$把原始不可序列化属性**拆包unwrap**成可序列化的形态存进代理对象序列化时先经writeReplace()写入代理反序列化时再由readResolve()从代理重建原对象。关于该扩展的适用前提源码注释 说得非常清楚必须同时满足两条该AutoValue类实现了Serializable类中不可序列化的属性必须有对应的SerializerExtension能够处理。二、快速上手2.1 两个硬性条件按照官方文档 的说明使用该扩展的AutoValue类必须满足实现java.io.Serializable标注SerializableAutoValue注解。SerializableAutoValue本身是个极简的SOURCE级别、只能标注在类型上的注解定义在 SerializableAutoValue.javaRetention(RetentionPolicy.SOURCE) Target(ElementType.TYPE) public interface SerializableAutoValue {}它本身不携带任何参数作用只是一个“开关”——激活SerializableAutoValueExtension。在处理器端扩展通过检查类上是否存在该注解来决定是否介入private static boolean hasSerializableAutoValueAnnotation(Context context) { return context.autoValueClass().getAnnotationMirrors().stream() .map(AnnotationMirror::getAnnotationType) ... .anyMatch(name - name.contentEquals(SERIALIZABLE_AUTO_VALUE_NAME)); }见 SerializableAutoValueExtension.java同时处理器还会用Types.isAssignable校验类确实实现了Serializableprivate static boolean hasSerializableInterface(Context context) { ... return context.processingEnvironment().getTypeUtils() .isAssignable(context.autoValueClass().asType(), serializableTypeMirror); }见 SerializableAutoValueExtension.java只有这两个条件同时满足applicable()才会返回 true扩展才会生效。2.2 一个完整的例子沿用官方文档示例一个不可序列化的 AutoValue 类是这样的AutoValue public abstract class Foo implements Serializable { public static Foo create(OptionalString x) { return new AutoValue_Foo(x); } // java.util.Optional 不可序列化 abstract OptionalString x; }只加一个注解即可“激活”扩展SerializableAutoValue // 这个注解激活扩展 AutoValue public abstract class Foo implements Serializable { // ...同上 }注意SerializableAutoValue与AutoValue叠加使用顺序无关紧要。添加注解后SerializableAutoValueExtension会作为AutoValueExtension的一个实现通过 AutoService 机制 被AutoValueProcessor发现并调用生成新的AutoValue_Foo子类。三、生成的代码长什么样3.1 writeReplace / readResolve / Proxy$官方文档给出了上面Foo的生成结果见 index.md它精准对应了 Java 序列化协议中的两个钩子方法Generated(SerializableAutoValueExtension) final class AutoValue_Foo extends $AutoValue_Foo { // 不直接序列化 AutoValue_Foo而是委托给代理对象 Object writeReplace() throws ObjectStreamException { return new Proxy$(this.x); } // 序列化时AutoValue_Foo 的值写入 Proxy$ // 反序列化时用 Proxy$ 的值重建 AutoValue_Foo static class Proxy$ implements Serializable { private String x; // 序列化阶段把 Optional 拆包 Proxy$(OptionalString x) { this.x x.orElse(null); } // 反序列化阶段重建 AutoValue_Foo Object readResolve() throws ObjectStreamException { return new AutoValue_Foo(Optional.ofNullable(x)); } } }整个机制可以概括为writeReplace把真实对象替换为代理 → 代理携带“可序列化形态”的字段被真正序列化 → 反序列化时readResolve把代理替换回真实对象。3.2 生成逻辑的源码落点这段生成代码的每一处都能在处理器源码中找到对应实现子类骨架extends $AutoValue_Foo、final修饰、Generated注解在 Generator.generate() 中构建其中Generated(SerializableAutoValueExtension)通过GeneratedAnnotationSpecs.generatedAnnotationSpec生成writeReplace()方法体在 Generator.writeReplace() 中生成它会为每个属性调用对应的 getter如this.x并把它们拼进new Proxy$(...)调用代理类Proxy$的完整生成逻辑在 ProxyGenerator包括serialVersionUID字段固定初始化为 0见 serialVersionUid()、代理字段、构造器与readResolve()。注意构造器与readResolve的“对称性”构造器参数是原始类型OptionalString x用serializer.toProxy转换为代理字段readResolve的返回值则用serializer.fromProxy把代理字段还原回原始类型。四、内置支持的类型4.1 三类内置序列化器按官方文档 的 Supported Types 清单扩展目前内置支持类型效果实现源码java.util.OptionalOptionalT整体不可序列化拆包为T的可序列化形态空则存nullOptionalSerializerExtension.javacom.google.common.collect.ImmutableList当T不可序列化但被支持时让ImmutableListT可序列化ImmutableListSerializerExtension.javacom.google.common.collect.ImmutableMap当K或V不可序列化但被支持时让ImmutableMapK, V可序列化ImmutableMapSerializerExtension.java这三个类都通过AutoService(SerializerExtension.class)注册会被ServiceLoader自动发现。4.2 嵌套式的逐层拆包内置扩展的精髓在于“递归拆包”。以OptionalSerializerExtension为例见 OptionalSerializerExtension.java判断类型是否为java.util.Optional通过 qualified name 匹配取出OptionalT里的T用factory.getSerializer(T)继续向下查询基于“内部类型的序列化器”构造OptionalSerializer。它的toProxy生成为isPresent() ? 内部转换 : nullfromProxy生成为Optional.ofNullable(内部还原)proxyFieldType直接复用内部类型的代理类型——也就是说OptionalFoo的代理类型就是Foo的代理类型。ImmutableListSerializerExtension更进一步源码当内部元素T已经是可序列化identity serializer时直接返回Optional.empty()表示“无需特殊处理”只有当T不可序列化时才生成逐元素映射的序列化器。生成的代码形态为list.stream().map(FunctionWithExceptions.wrapper(e - /* 逐元素 toProxy */)) .collect(ImmutableList.toImmutableList())ImmutableMapSerializerExtension同理源码只有当键和值都是 identity 时才跳过否则对 key 与 value 分别做映射生成entrySet().stream().collect(ImmutableMap.toImmutableMap(...))形态的代码。之所以能用 lambda 形式生成流式映射代码是因为扩展额外提供了一个运行时工具类 FunctionWithExceptions.java把可能抛受检异常的转换函数包装为java.util.function.Function。4.3 各类型组合的“代理形态”速查基于各内置扩展的proxyFieldType实现可以总结出常见组合的拆包结果供理解生成代码使用OptionalString→ 代理字段String空 Optional 存nullOptionalFooFoo 有自定义序列化器→ 代理字段为Foo的代理类型ImmutableListFoo→ImmutableListFoo的代理类型ImmutableMapK, V→ImmutableMapK的代理类型, V的代理类型。五、为自定义类型编写 SerializerExtension5.1 核心接口与三要素内置类型毕竟有限业务上总有自定义的不可序列化类型。官方文档在 serializer-extension.md 中给出了完整的扩展指南其核心是SerializerExtension与Serializer两个接口定义在 interfaces 目录。SerializerExtension只有一个方法SerializerExtension.javaOptionalSerializer getSerializer( TypeMirror type, SerializerFactory factory, ProcessingEnvironment processingEnv);当SerializableAutoValueExtension处理AutoValue类的每个属性时会依次询问每个SerializerExtension“这个类型你能处理吗”能处理就返回非空的Serializer不能就返回Optional.empty()。Serializer接口定义了三个抽象方法加一个默认方法Serializer.java对应文档所说的三件事TypeMirror proxyFieldType()—— 从原始属性类型推导出合适的可序列化代理类型CodeBlock toProxy(CodeBlock expression)—— 生成把原始值映射为代理值的表达式CodeBlock fromProxy(CodeBlock expression)—— 生成把代理值映射回原始值的表达式default boolean isIdentity()—— 是否为恒等序列化器默认返回 false。其中CodeBlock是 JavaPoet 的代码片段类型负责在编译期生成 Java 代码。5.2 完整的自定义扩展示例沿用官方文档的Bar例子serializer-extension.md。假设有个不可序列化的类// 一个不可序列化的类 public final class Bar { public int x; public Bar(int x) { this.x x; } }以及一个含Bar属性的 AutoValue 类SerializableAutoValue AutoValue public abstract class Foo implements Serializable { public static Foo create(Bar bar) { return new AutoValue_Foo(bar); } // Bar 不可序列化 abstract Bar bar(); }我们的思路是把Bar拆包为它的可序列化字段int x。编写如下扩展// 用 AutoService 让 BarSerializerExtension 可被 java.util.ServiceLoader 发现 AutoService(SerializerExtension.class) public final class BarSerializerExtension implements SerializerExtension { // 服务提供者必须有无参公共构造器 public BarSerializerExtension() {} // 该方法会对 AutoValue 的每个属性调用。 // 当扩展能处理某类型即 Bar时就返回一个 Serializer。 Override public OptionalSerializer getSerializer( TypeMirror type, SerializerFactory factory, ProcessingEnvironment env) { // BarSerializerExtension 只处理 Bar 类型 if (!isBar(type)) { return Optional.empty(); } return Optional.of(new BarSerializer(env)); } // 我们对 Bar 序列化/反序列化的具体实现 private static class BarSerializer implements Serializer { private final ProcessingEnvironment env; BarSerializer(ProcessingEnvironment env) { this.env env; } // 序列化 Bar 的一种方式是只序列化 Bar.x即把 Bar 映射为 int Override public TypeMirror proxyFieldType() { return Types.getPrimitiveType(TypeKind.INT); } // 把 Bar 映射到 proxyFieldType 声明的类型。 // 注意expression 是类型为 Bar 的变量。 Override public CodeBlock toProxy(CodeBlock expression) { return CodeBlock.of($L.x, expression); } // 把整数映射回 Bar Override public CodeBlock fromProxy(CodeBlock expression) { return CodeBlock.of(new $T($L), Bar.class, expression); } } }这段代码里有几个官方文档特别强调的要点必须使用AutoService(SerializerExtension.class)这是 Auto 项目提供的注解处理器位于 service 模块编译期为扩展自动生成META-INF/services/...注册文件从而被java.util.ServiceLoader发现必须提供 public 无参构造器这是ServiceLoader对服务提供者的硬性要求getSerializer里返回Optional.empty()表示“我处理不了这个类型”扩展框架会继续询问下一个扩展。5.3 扩展生效后的生成代码加入BarSerializerExtension后SerializableAutoValueExtension为Foo生成的代码变成官方文档Generated(SerializableAutoValueExtension) final class AutoValue_Foo extends $AutoValue_Foo { Object writeReplace() throws ObjectStreamException { return new Proxy$(this.x); } static class Proxy$ implements Serializable { // 类型由 BarSerializer#proxyFieldType 生成 private int bar; Proxy$(Bar bar) { // 赋值表达式由 BarSerializer#toProxy 生成 this.bar bar.x; } Object readResolve() throws ObjectStreamException { // 反向映射表达式由 BarSerializer#fromProxy 生成 return new AutoValue_Foo(new Bar(bar)); } } }可以看到代理字段的类型int、构造器里的bar.x、readResolve里的new Bar(bar)分别对应你实现的三个方法扩展本身只是把这些代码片段按固定骨架组装起来。六、支持带类型参数的泛型类型SerializerExtension同样支持泛型类型。官方文档以BazT为例serializer-extension.md// 一个可能不可序列化的类取决于 T 的实际类型 public final class BazT implements Serializable { public T x; public Baz(int x) { this.x x; } }BazT的泛型参数T可能不可序列化。此时扩展的关键技巧是通过SerializerFactory查询T的序列化器再“借用”它来序列化BazAutoService(SerializerExtension.class) public final class BazSerializerExtension implements SerializerExtension { public BazSerializerExtension() {} Override public OptionalSerializer getSerializer( TypeMirror type, SerializerFactory factory, ProcessingEnvironment env) { if (!isBaz(type)) { return Optional.empty(); } // 取出 BazT 里的 T TypeMirror containedType getContainedType(type); // 为 T 查找序列化器 Serializer containedTypeSerializer factory.getSerializer(containedType); // 如果 T 的序列化器是恒等的说明 T 可序列化或不受支持 // 无论哪种情况都不需要额外处理Baz 可以原样序列化 if (containedTypeSerializer.isIdentity()) { return Optional.empty(); } // 借助 T 的序列化器让 Baz 可序列化 return Optional.of(new BazSerializer(containedTypeSerializer)); } private static class BazSerializer implements Serializer { private Serializer serializer; BazSerializer(Serializer serialize) { this.serializer serializer; } Override public TypeMirror proxyFieldType() { // 既然 T 是 Baz 唯一的字段Baz 就映射为 T 的代理类型 return serializer.proxyFieldType(); } Override public CodeBlock toProxy(CodeBlock expression) { return serializer.toProxy(expression); } Override public CodeBlock fromProxy(CodeBlock expression) { return serializer.fromProxy(expression); } } }注意源码中getSerializer内的参数名是factory而构造器赋值处源码写作this.serializer serializer即代码清单中的BazSerializer(Serializer serialize)只是形参命名无碍逻辑。核心思想是先问“内部类型有没有序列化器”有就用它的代理类型与转换表达式没有就返回 empty 让Baz原样序列化。需要留意isIdentity()的语义Serializer.java恒等序列化器意味着“类型无需转换”既包括本来就可序列化的类型也包括没有任何扩展认领、被兜底处理的类型。BazSerializerExtension正是利用这一点判断“Baz 是否真的需要特殊处理”。七、底层运行机制从注解到代理类7.1 扩展的触发链路把整条链路串起来从注解到最终代码的流程是AutoValueProcessor处理AutoValue类时通过ServiceLoader发现所有AutoValueExtension实现见 SerializableAutoValueExtension.java 上的AutoService(AutoValueExtension.class)调用applicable(context)判断类是否实现Serializable且带有SerializableAutoValue注解源码满足条件后进入generateClass由内部类Generator组织生成逻辑源码。7.2 SerializerFactory 的装配与兜底Generator的构造过程源码会为每个去重后的属性类型查询一次序列化器并缓存成serializersMapSerializerFactory factory SerializerFactoryLoader.getFactory(context.processingEnvironment()); return propertyMirrors.stream() .map(PropertyMirror::getType) .map(MoreTypes.equivalence()::wrap) .distinct() .collect(toImmutableMap(Function.identity(), equivalence - factory.getSerializer(equivalence.get())));SerializerFactoryLoader源码负责加载所有SerializerExtension并交给SerializerFactoryImpl。而SerializerFactoryImpl源码的查询策略是Override public Serializer getSerializer(TypeMirror typeMirror) { for (SerializerExtension extension : extensions) { OptionalSerializer serializer extension.getSerializer(typeMirror, this, env); if (serializer.isPresent()) { return serializer.get(); // 找到第一个能处理的扩展 } } return IdentitySerializerFactory.getSerializer(typeMirror); // 兜底恒等序列化 }即按注册顺序依次询问扩展第一个返回非空Serializer的胜出如果没有任何扩展能处理该类型则回退到恒等序列化器IdentitySerializerFactory.java原样保留字段类型。这也解释了为什么文档说“每个属性都会被尝试查找扩展”可序列化的普通类型最终都会落到 identity 分支代理字段保持原类型不变。另外SerializerFactoryImpl.newIdentifier()用AtomicInteger生成形如value$1、element$2的唯一局部变量名源码保证流式映射生成的 lambda 参数不会与用户代码中的标识符冲突——这也是SerializerFactory接口提供该方法的原因。7.3 增量编译支持SerializableAutoValueExtension声明了自己的增量编译类型为ISOLATING源码即每个类型只依赖其自身改动后只需重新编译受影响的类型对构建系统如 Gradle、Maven 的增量编译友好。7.4 如何把扩展加入构建官方文档在 serializer-extension.md 说明使用第三方扩展只需把该扩展 jar 加入AutoValue类所在模块的依赖中ServiceLoader会在编译期自动发现编写自己的扩展把实现类连同SerializerExtension接口一起放在-processorpath注解处理路径上并借助AutoService生成服务注册文件。从SerializerExtension接口的 JavadocSerializerExtension.java可以确认扩展必须满足“public 类 public 无参构造器”并且其全限定名必须出现在META-INF/services/com.google.auto.value.extension.serializable.serializer.interfaces.SerializerExtension文件中该文件需位于编译器的-classpath或-processorpath上的某个 jar 里——AutoService正是自动完成这一注册的。7.5 测试验证仓库中对应的测试文件可以验证上述行为的正确性SerializableAutoValueExtensionTest.java 覆盖扩展的生成逻辑与集成行为IdentitySerializerFactoryTest.java、OptionalSerializerExtensionTest.java、ImmutableListSerializerExtensionTest.java、ImmutableMapSerializerExtensionTest.java 分别针对各内置序列化器做单元验证SerializerFactoryLoaderTest.java 验证扩展发现机制。八、已知边界与使用建议适用范围该扩展只对“实现了Serializable且带SerializableAutoValue注解”的AutoValue类生效两者缺一不可普通AutoValue类不受影响内置支持有限目前仅覆盖Optional、ImmutableList、ImmutableMap三类其他不可序列化类型需要自己写扩展代理字段的可序列化性代理类Proxy$本身的字段类型由各序列化器的proxyFieldType()决定自定义扩展时务必保证返回的代理类型本身可序列化否则会引入新的序列化失败点性能与体积writeReplace/readResolve会在每次序列化往返中多一次对象创建代理类也会增加生成的代码量对于高频序列化的场景需自行权衡与AutoValue生成代码的关系扩展生成的是新的AutoValue_Foo子类它extends原AutoValueProcessor生成的$AutoValue_Foo带$前缀的中间类因此原有 equals/hashCode/toString 逻辑完全保留代理机制只是在最外层包了一层序列化壳。总结SerializableAutoValueExtension用一个“编译期代理”的巧妙设计解决了AutoValue值对象因属性不可序列化而整体不可序列化的痛点开箱即用只需implements SerializableSerializableAutoValue即可让含Optional、ImmutableList、ImmutableMap的类可序列化机制透明生成的Proxy$writeReplace/readResolve完全符合 Java 序列化协议无需运行时反射或额外框架高度可扩展通过实现SerializerExtension与Serializer两个接口任何不可序列化类型都能获得“拆包 → 存代理 → 还原”的能力泛型类型还可借助SerializerFactory递归复用内部类型的序列化器。如果你正在为 AutoValue 类中的不可序列化字段头疼这个扩展及其扩展点就是官方提供的标准解法。进一步阅读可参考 官方文档、SerializerExtension 指南 以及 value 模块整体说明。赞分享代码生成开发工具【免费下载链接】autoA collection of source code generators for Java.项目地址https://gitcode.com/gh_mirrors/auto/auto点击查看免费下载相关推荐LunaTranslator 快速教程10 分钟让一款日文游戏跑通翻译LunaTranslator 快速教程10 分钟让一款日文游戏跑通翻译 你离看懂一行日语只差 30 秒选中文本、切到浏览器、粘进翻译网站、再切回来——结果出开发工具代码生成AutoValue SerializableAutoValue 扩展开发指南用 SerializerExtension 为任意非可序列化类型接入 Java 序列化AutoValue SerializableAutoValue 扩展开发指南用 SerializerExtension 为任意非可序列化类型接入 Java 序开发工具代码生成WandEnhancer本地解锁 WeMod Pro 的完整指南WandEnhancer本地解锁 WeMod Pro 的完整指南 如果你还在为 WeMod Pro 的订阅费纠结或者被免费版里的广告和时长限制打断游戏体验代码生成开发工具上一篇基于 Rube MCP 自动化 Browserhub 任务awesome-codex-skills 中的 Browserhub Automation 技能实战指南下一篇10个必学的Linux内核安全研究从linux-kernel-exploits看安全攻防创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
