MetadataCollectionTransformer

基本信息

属性 值
类 com.mitchej123.jarjar.rfb.transformer.MetadataCollectionTransformer
Transformer ID jarjar-serializednametransformer
RFB 排序 sortBefore = ["*"]
目标类 cpw.mods.fml.common.MetadataCollection
目标字段 modList

为 MetadataCollection.modList 字段注入 Gson @SerializedName 注解的 modlist/ModList 别名。原版 FML 的 Gson 序列化只接受 modList,但许多 modpack 在打包工具生成 mcmod.info 时把字段写成 modlist(小写 L)或 ModList(PascalCase),导致反序列化得到空 modList 数组。

ASM 注入

private static final String TARGET_CLASS = "cpw.mods.fml.common.MetadataCollection";
private static final String TARGET_FIELD = "modList";
private static final String SERIALIZED_NAME_DESC = "Lcom/google/gson/annotations/SerializedName;";

public boolean shouldTransformClass(...) {
    return TARGET_CLASSES.contains(className);  // 只命中 MetadataCollection
}

public void transformClass(...) {
    final ClassNode cn = classNode.getNode();
    if (cn == null || cn.fields == null) return;

    for (FieldNode field : cn.fields) {
        if (field.name.equals(TARGET_FIELD)) {
            boolean hasAnnotation = false;
            if (field.visibleAnnotations != null) {
                for (AnnotationNode annotation : field.visibleAnnotations) {
                    if (annotation.desc.equals(SERIALIZED_NAME_DESC)) { hasAnnotation = true; break; }
                }
            }
            if (!hasAnnotation) {
                AnnotationNode annotation = new AnnotationNode(SERIALIZED_NAME_DESC);
                annotation.values = new ArrayList<>();
                annotation.values.add("value");
                annotation.values.add("modList");
                annotation.values.add("alternate");
                annotation.values.add(Arrays.asList("modlist", "ModList"));
                if (field.visibleAnnotations == null) field.visibleAnnotations = new ArrayList<>();
                field.visibleAnnotations.add(annotation);
            }
            break;
        }
    }
}

注入的注解等价于:

@SerializedName(value = "modList", alternate = {"modlist", "ModList"})
public ModMetadata[] modList;

触发场景

Modpack 打工具链(典型 CurseForge / Modrinth / 自建脚本)生成 mcmod.info 时常常把首字母小写或 PascalCase 化。原版 FML 1.7.10 的 Gson 反序列化用 @SerializedName 找不到匹配键,整字段返回空数组 → ModContainer.bindMetadata() 拿不到 modId/name/version → mod 名/版本显示异常。

与 MetadataCollectionV2 的协作

MetadataCollectionTransformer 处理"字段别名",MetadataCollectionV2.from(InputStream, ...) 处理"JSON 顶层是数组 vs 对象"两种结构(modListVersion: 2)。两者覆盖了 mcmod.info 的两个常见解析失败路径。

相关条目