【问题标题】:Case insensitive XMLEnumValue in JAXBJAXB 中不区分大小写的 XMLEnumValue
【发布时间】:2014-07-29 07:39:30
【问题描述】:

JAXB 允许使用 @XMLEnum 注释直接从 XML 中定位 Enum 实例。 从@XMLEnumValue 定位值时,JAXB 似乎区分大小写。

但我面临一个问题,我需要以 不区分大小写 的方式定位 Enum 实例。 JAXB 是否以某种方式提供此功能? 如果没有这个,我会遇到手动定位枚举常量的问题。

我可以为此使用XMLAdapter,但是为每个创建的枚举维护一个适配器变得非常乏味。

编辑:

为什么必须以不区分大小写的方式定位枚举?

因为我正在使用 xml 来读取我的系统的配置,并且我不希望用户被限制在固定大小写。我希望这能回答你的问题。

public class CaseInsensitiveEnumAdapter<E extends Enum<E>> extends XmlAdapter<String, E> {

    private final Class<E> clazz;

    public CaseInsensitiveEnumAdapter(Class<E> clazz) {
        this.clazz = clazz;
    }

    @Override
    public E unmarshal(String v) throws Exception {
        return Enum.<E>valueOf(clazz, v.toUpperCase().trim());
    }

    @Override
    public String marshal(E v) throws Exception {
        return v.name();
    }
}

由于我需要 .class 用于枚举,因此我必须为所有枚举创建单独的适配器。

【问题讨论】:

  • 为什么必须以不区分大小写的方式定位枚举?
  • @JamesB 我已经更新了帖子来回答你的问题。
  • 如果不强制用户输入区分大小写的数据,您能否轻松识别 XML 文本内容中的枚举?如果是这样,您可以在将其提供给 JAXB 之前将其转换为大写。
  • 另外,我不明白为什么不能为所有枚举值使用一个 XMLAdapter?你能把这段代码贴出来吗?
  • 我相信这对于 JAXB 是不可能的。我想出于实际原因这是不可能的 - 在编组过程中会出现问题。对于枚举:public enum DayOfWeek {MONDAY} 假设有一个注释可以忽略枚举的大小写。这在解组期间会很好,因此“MonDAY”、“MONDAY”、“monday”都可以解析为 DayOfWeek.MONDAY。编组时,将编组的“版本”会有问题。也许您提供一个默认值进行编组的实现是可能的。但我不知道在 JAXB 中有任何解决此问题的方法。

标签: java xml enums jaxb


【解决方案1】:

好心的纳伦德拉先生,

我想出了一个基于正则表达式的解决方案。 这个想法是将模式限制与能够接受任何大小写组合的正则表达式一起使用。 我创建了一个列举三种颜色的示例:绿色、红色和蓝色。 以下常规异常将接受“GrEEn”和“gReeN”文字作为有效值:

g|Gr|Re|Ee|En|N

在示例文件下:

示例 XML 架构

<xs:simpleType name="ColorType" final="restriction" >
    <xs:restriction base="xs:string">
        <xs:pattern value="g|Gr|Re|Ee|En|N" />
        <xs:pattern value="r|Re|Ed|D" />
        <xs:pattern value="b|Bl|Lu|Ue|E" />
    </xs:restriction>
</xs:simpleType>
<xs:element name="SomeElement">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="Color" type="ColorType" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

XML 案例 1

<SomeElement>
    <Color>GreEN</Color>
</SomeElement>

XML 案例 2

<SomeElement>
    <Color>gREen</Color>
</SomeElement>

JUnit

public class TestJaxb {

    private static final String GREEN = "GREEN";

    @Test
    public void shouldParseCase1() throws JAXBException, MalformedURLException {
        URL xmlUrl = // Load XML file 1
        SomeElement someElement = parse(xmlUrl, SomeElement.class);
        assertEquals(GREEN, someElement.getColor().toUpperCase());
    }

    @Test
    public void shouldParseCase2() throws JAXBException, MalformedURLException {
        URL xmlUrl = // Load XML file 2
        SomeElement someElement = parse(xmlUrl, SomeElement.class);
        assertEquals(GREEN, someElement.getColor().toUpperCase());
    }

    private <T> T parse(URL url, Class<T> clazz) throws JAXBException {
        Unmarshaller unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller();
        return clazz.cast(unmarshaller.unmarshal(url));
    }
}

我意识到这会使您的 XSD 规范的用户更难理解枚举中允许哪些值,但也许评论对您来说就足够了。

事实上,我发现没有其他方法可以在不实际更改 JAXB 代码的情况下实现此目的。

希望这会有所帮助。

最好的问候

【讨论】:

  • 我认为你误解了这个问题。问题是关于如何实现 @Xml... 带注释的 bean,以便从包含与实际枚举常量不同的枚举值的 XML 反序列化。
  • 您好 @SteffenHarbich 在问题的 cmets 中有人已经说过这是不可行的,所以我提出了另一个想法来实现用户真正需要的,即不区分大小写的解组。
  • 好的,基本上你做了一个toUpperCase ——至少对我来说——已知是有效的。我开始赏金是因为我认为在最初发布问题的过去 5 年内可能会有新功能或其他东西。但不幸的是,似乎没有。
  • 并非如此,如果没有 XSD 中的模式,当 XML 输入与硬编码模式版本不同时,XJC 编译器将无法解组。我认为我可以在 JAXB 中实现这样的功能,但我没有研究它,所以我不知道实际的复杂性。很抱歉,这更多是为了解决 OP,甚至没有注意到线程日期:D 干杯!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-01
  • 2013-03-06
  • 2020-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-17
相关资源
最近更新 更多