You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JAXB自定义绑定在XJC代码生成时将List<LangStringWrapper>转换为Map<String, String>

如何通过JAXB自定义绑定在XJC代码生成时将List转换为Map<String, String>

我之前刚好踩过这个坑,为了把重复的LangString元素转成Map折腾了好一阵,终于摸清楚了完整的实现流程,下面把步骤一步步讲清楚,亲测能用~

首先得确认你的XSD里LangString的结构,应该是类似这样的吧?就是带一个lang属性的字符串扩展类型:

<xs:complexType name="LangString">
  <xs:simpleContent>
    <xs:extension base="xs:string">
      <xs:attribute name="lang" type="xs:string" use="required"/>
    </xs:extension>
  </xs:simpleContent>
</xs:complexType>

如果你的结构是包裹在LangStringWrapper里的(比如Wrapper类包含lang和value字段),核心思路也一样,只是后面转换器里的对象调用要对应调整。

第一步:编写XJC自定义绑定文件

创建一个绑定文件(比如叫bindings.xjb),这是告诉XJC怎么生成我们想要的Map类型的核心配置,有两种配置方式可以选:

方式一:全局配置(所有重复LangString元素都转Map)

如果项目里所有重复的LangString都要转成Map,用这种方式最省心:

<jaxb:bindings version="2.1"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <!-- 全局绑定规则:把LangString类型的重复实例映射为Map -->
    <jaxb:globalBindings>
        <jaxb:javaType name="java.util.Map&lt;String, String&gt;"
                       xmlType="xs:LangString"
                       parseMethod="com.yourpackage.LangStringConverter.parseLangStrings"
                       printMethod="com.yourpackage.LangStringConverter.printLangStrings"/>
    </jaxb:globalBindings>

</jaxb:bindings>

方式二:局部配置(仅针对特定元素转Map)

如果只有某个特定的重复LangString元素需要转Map,就用这种精准定位的方式,比如XSD里Product类型下的description元素是重复的LangString:

<jaxb:bindings version="2.1"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <jaxb:bindings schemaLocation="your-schema.xsd">
        <!-- 定位到Product类型下的description元素 -->
        <jaxb:bindings node="//xs:complexType[@name='Product']/xs:sequence/xs:element[@name='description']">
            <jaxb:property>
                <jaxb:baseType name="java.util.Map&lt;String, String&gt;"/>
                <jaxb:javadoc>键是lang属性值,值是文本内容</jaxb:javadoc>
            </jaxb:property>
        </jaxb:bindings>
    </jaxb:bindings>

</jaxb:bindings>

第二步:编写类型转换器类

XJC本身没法直接把带属性的元素集合转成Map,所以我们得自己写一个转换器类,用来在List<LangString>(或List<LangStringWrapper>)和Map<String, String>之间做双向转换——既能支持代码生成时转成Map,也能保证后续XML序列化正常工作。

比如创建com.yourpackage.LangStringConverter,代码如下:

package com.yourpackage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// 这里导入XJC默认生成的类,如果是LangStringWrapper就替换成对应的
import com.yourpackage.generated.LangString;

public class LangStringConverter {

    // 把LangString列表转成Map:lang属性当键,文本内容当值
    public static Map<String, String> parseLangStrings(List<LangString> langStrings) {
        Map<String, String> langMap = new HashMap<>();
        if (langStrings == null) return langMap;
        
        for (LangString ls : langStrings) {
            // 如果lang属性可能为空,这里可以加判断,比如给默认键"en"
            langMap.put(ls.getLang(), ls.getValue());
        }
        return langMap;
    }

    // 把Map转回LangString列表,用于XML序列化
    public static List<LangString> printLangStrings(Map<String, String> langMap) {
        List<LangString> langStrings = new ArrayList<>();
        if (langMap == null) return langStrings;
        
        for (Map.Entry<String, String> entry : langMap.entrySet()) {
            LangString ls = new LangString();
            ls.setLang(entry.getKey());
            ls.setValue(entry.getValue());
            langStrings.add(ls);
        }
        return langStrings;
    }
}

如果是LangStringWrapper,只要把代码里的LangString替换成LangStringWrapper,然后调用对应的getter/setter方法(比如wrapper.getLang()、wrapper.setValue())就行。

第三步:用XJC生成代码

命令行方式

直接在命令行指定绑定文件和XSD文件:

xjc -d 生成代码的输出目录 -b bindings.xjb 你的XSD文件路径.xsd

Maven项目方式

如果用Maven管理项目,在pom.xml里配置jaxb2-maven-plugin,加上绑定文件路径:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <version>2.5.0</version>
    <executions>
        <execution>
            <goals>
                <goal>xjc</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <schemaDirectory>${project.basedir}/src/main/resources/xsd</schemaDirectory>
        <bindingDirectory>${project.basedir}/src/main/resources</bindingDirectory>
        <bindingFiles>bindings.xjb</bindingFiles>
        <outputDirectory>${project.build.directory}/generated-sources/jaxb</outputDirectory>
    </configuration>
</plugin>

执行mvn clean install后,就能在指定目录看到生成的类——原本是List<LangString>的字段已经变成Map<String, String>了。

一些要注意的小细节

  • 确保XSD里的LangString元素是maxOccurs="unbounded"的,也就是允许重复出现,不然XJC只会生成单个实例,没法转成Map。
  • 如果lang属性不是必填项,转换器里要处理null键的情况,比如给默认值或者跳过,避免空指针异常。
  • 转换器类的包路径要和绑定文件里写的完全一致,不然XJC会找不到转换器直接报错。

我当时就是这么配置的,生成的代码完全符合预期,你可以根据自己的实际XSD结构调整绑定文件和转换器的细节~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 13:28:02