MOXy:DynamicJAXBContext错误地处理XSD枚举文字(@XmlEnumValue)

问题描述 投票:-1回答:1

问题:使用DynamicJAXBContext时,由MOXy生成的枚举的映射(用2.7.4、2.7.5测试)显示出不希望的(明晰的)行为:

  1. XML源中期望的值对应于the java.lang.Enum.name(),而不是XSD中定义的文字。例如:给定XSD枚举文字fooValue,MOXy期望FOO_VALUE
  2. 即使java.lang.Enum.name()在XML源中使用(已经很骇人了!),动态生成的java.lang.Enum常量也缺少@XmlEnumValue批注。这将导致在编组时生成无效的XML:考虑前面的示例,Marshaller将写入FOO_VALUE而不是fooValue

问题:有什么办法可以改善这种行为?我可以忍受问题1,但是问题2使MOXy对我来说完全无法使用。

复制:

JUnit-Test(为简便起见,省略了导入)(失败):

  @Test
  public void test_xmlEnumValue() throws Exception {
    String resourcesBasePath = "src/test/resources/enums/";
    FileInputStream xsdInputStream = new FileInputStream(resourcesBasePath + "EnumSchema.xsd");
    DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromXSD(xsdInputStream, null, null, null);
    JAXBUnmarshaller unmarshaller = jaxbContext.createUnmarshaller();

    File inputFile = new File(resourcesBasePath + "EnumSchemaInstance.xml");
    StreamSource xmlInputStreamSource = new StreamSource(inputFile);
    JAXBElement<DynamicEntity> dynamicEntity = (JAXBElement<DynamicEntity>) unmarshaller.unmarshal(xmlInputStreamSource);
    Enum testEnumValue = (Enum) dynamicEntity.getValue().get("testEnumValue");
    assertThat(testEnumValue.name(), IsEqual.equalTo("FOO_VALUE"));
  }

EnumSchema.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://acme.com/test" targetNamespace="http://acme.com/test"
    elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0">
    <xs:element name="test" type="tns:TestType" />
    <xs:complexType name="TestType">
        <xs:sequence>
            <xs:element name="testEnumValue" type="tns:TestEnum" />
        </xs:sequence>
    </xs:complexType>
    <xs:simpleType name="TestEnum">
        <xs:restriction base="xs:string">
            <xs:enumeration value="fooValue" />
            <xs:enumeration value="Bar_Value" />
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

EnumSchemaInstance.xml:

<test xmlns="http://acme.com/test">
    <testEnumValue>fooValue</testEnumValue>
</test>

进一步的研究:

[我仍然可以在@XmlEnumValue上找到EnumTypeInfo注释的最新时间是org.eclipse.persistence.jaxb.compiler.MappingsGenerator.buildJAXBEnumTypeConverter(Mapping, EnumTypeInfo)

private JAXBEnumTypeConverter buildJAXBEnumTypeConverter(Mapping mapping, EnumTypeInfo enumInfo){
    JAXBEnumTypeConverter converter = new JAXBEnumTypeConverter(mapping, enumInfo.getClassName(), false);
    List<String> fieldNames = enumInfo.getFieldNames();
    List<Object> xmlEnumValues = enumInfo.getXmlEnumValues();
    for (int i=0; i< fieldNames.size(); i++) {
        converter.addConversionValue(xmlEnumValues.get(i), fieldNames.get(i));
    }
    return converter;
}

此时的问题似乎是fieldNamesxmlEnumValues都只包含一个值:value。考虑到此时可以通过使用JEnumConstant中正确注释的com.sun.codemodel.JDefinedClass.enumConstantsByName来获得正确的值,这几乎没有用。由于此方法创建的映射现在仅将"value"映射到"value",因此缺少的值将在以后的时间点映射,在此处org.eclipse.persistence.jaxb.JAXBEnumTypeConverter.initialize(DatabaseMapping, Session)

public void initialize(DatabaseMapping mapping, Session session) {
    Iterator<Enum> i = EnumSet.allOf(m_enumClass).iterator();
    while (i.hasNext()) {
        Enum theEnum = i.next();
        if (this.getAttributeToFieldValues().get(theEnum) == null) {
            Object existingVal = this.getAttributeToFieldValues().get(theEnum.name());
            if (existingVal != null) {
                this.getAttributeToFieldValues().remove(theEnum.name());
                addConversionValue(existingVal, theEnum);
            } else {
                // if there's no user defined value, create a default
                if (m_usesOrdinalValues) {
                    addConversionValue(theEnum.ordinal(), theEnum);
                } else {
                    addConversionValue(theEnum.name(), theEnum);
                }
            }
        }
    }

    super.initialize(mapping, session);
}

不使用序数值,现在映射将在一侧使用java.lang.Enum.name()->问题1),而在另一侧使用java.lang.Enum本身。但是,由于java.lang.Class.getFields()的字段(即java.lang.Enum)缺少@XmlEnumValue批注,因此编组创建的XML也将包含java.lang.Enum.name()(([[->问题2]

EnumSchemaInstance.xml中的XML链以包含java.lang.Enum.name(),即e。:

<?xml version="1.0" encoding="UTF-8"?> <test xmlns="http://acme.com/test"> <testEnumValue>FOO_VALUE</testEnumValue> </test>

导致通过映射找到java.lang.Enum,进一步验证了问题1。现在,如果再次将JAXBElement<DynamicEntity> dynamicEntity编组为这样:

JAXBMarshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(JAXBMarshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(dynamicEntity, System.out);

XML输出显示java.lang.Enum.name(),进一步验证问题2:

<?xml version="1.0" encoding="UTF-8"?> <test xmlns="http://acme.com/test"> <testEnumValue>FOO_VALUE</testEnumValue> </test>

EDIT:

链接到EclipseLink Bugzilla:https://bugs.eclipse.org/bugs/show_bug.cgi?id=552902
java enums jaxb moxy
1个回答
0
投票

TL; DR:

© www.soinside.com 2019 - 2024. All rights reserved.