【问题标题】:Custom enum marshaling with JAXB and moxy使用 JAXB 和 moxy 自定义枚举编组
【发布时间】:2015-07-05 12:30:53
【问题描述】:

我在使用 Moxy 和 JSON 进行自定义枚举编组时遇到了一些问题。我的用例是我有一个大型对象模型,其中包括通常应该提供正常枚举值、“代码”和描述的枚举。该数据的来源只有“代码”,因此我需要能够仅使用代码来解组​​这些枚举的实例(例如

{"companyCode":{"code":"PI"}}。

但是,我也应该能够编组和解组所有三个字段:

{"companyCode":
  {"value":"Private",
  "code":"PI","description":
  "Private Ins"
  }
}


我正在使用如下所示的适配器:

public class CodeEnumXmlAdapter<E extends Enum<E> & CodeEnum> extends XmlAdapter<CodeEnumImpl,E> {

    public static <T extends Enum<T> & CodeEnum> T getFromName(Class<T> clazz, String name) {
        if (name == null) return null;

        T[] values = clazz.getEnumConstants();

        for (T t : values) {
            if (name.equals(t.name())) {
                return t;
            }
        }

        return null;
    }
    public static <T extends Enum<T> & CodeEnum> T getFromCode(Class<T> clazz, String code) {
        if (code == null) return null;

        T[] values = clazz.getEnumConstants();

        for (T t : values) {
            if (code.equals(t.getCode())) {
                return t;
            }
        }

        return null;
    }
    public static <T extends Enum<T> & CodeEnum> T getFromString(Class<T> clazz, String aString) {
        if (aString == null) return null;

        T[] values = clazz.getEnumConstants();

        for (T t : values) {
            if (aString.equals(t.getCode()) || aString.equals(t.name()) || aString.equals(t.getDescription())) {
                return t;
            }
        }

        return null;
    }

    @Override
    public E unmarshal(CodeEnumImpl value) throws Exception {
        if (value == null) return null;

        String valueString = value.getValue();
        if (valueString == null)
            valueString = value.getCode();
        if (valueString == null)
            valueString = value.getDescription();
        if (valueString == null)
            return null;

        Type generic = ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        return getFromString((Class<E>)generic, valueString);
    }

    @Override
    public CodeEnumImpl marshal(E value) throws Exception {
        return value == null ? null : new CodeEnumImpl(value);
    }
}

这会从这样的枚举转换:

import org.apache.commons.lang3.StringUtils;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlJavaTypeAdapter(CompanyCode.Adapter.class)
public enum CompanyCode implements CodeEnum {

    // Changed "Commmercial" to "Client" based on inputs from ...Greg, Tamil
    Client("CM", "Client"), Medicare("MC", "Medicare"), Medicaid("MD",
            "Medicaid"), Private("PI", "Private Ins"), Patient("PT", "Patient");

    private String code;
    private String description;

    private CompanyCode(String code, String label) {
        this.code = code;
        this.description = label;
    }

    public String getDescription() {
        return description;
    }

    public String getCode() {
        return code;
    }

    public static CompanyCode fromCode(String code) {
        if (StringUtils.isEmpty(code)) {
            return null;
        }

        for (CompanyCode freq : values()) {
            if (freq.getCode().equalsIgnoreCase(code)) {
                return freq;
            }
        }
        throw new IllegalArgumentException("Invalid CompanyCode code: " + code);
    }

    public String toString() {
        return description;
    }

    public static class Adapter extends CodeEnumXmlAdapter<CompanyCode> {}
}

并像这样使用和中间类型:

import javax.xml.bind.annotation.XmlElement;

/**
 * Created by Jeffrey Hoffman on 6/24/2015.
 */
public class CodeEnumImpl  {
    String value;
    String description;
    String code;

    public CodeEnumImpl() {

    }
    public <E extends Enum<E> & CodeEnum> CodeEnumImpl(E value) {
        if (value != null) {
            this.value = value.name();
            this.description = value.getDescription();
            this.code = value.getCode();
        }
    }

    @XmlElement
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @XmlElement
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @XmlElement
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return value == null ? null : value.toString();
    }
}

这适用于直接的 XML 和 JAXB。但是,当我尝试使用 Moxy 时,会出现如下异常:

异常描述:对象 [Private Ins],属于类 [class com.labcorp.phoenix.biz.enums.CompanyCode],无法转换为 [类 java.lang.Object]。内部异常:异常 [EclipseLink-115](Eclipse 持久性服务 - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DescriptorException 异常 说明:没有为属性 [Private] 提供转化价值。 映射: org.eclipse.persistence.oxm.mappings.XMLDirectMapping[companyCode-->companyCode/text()] 描述符:XMLDescriptor(com.labcorp.phoenix.eligibility.Root --> [数据库表(根)])在 org.eclipse.persistence.exceptions.ConversionException.couldNotBeConverted(ConversionException.java:87) 在 org.eclipse.persistence.internal.jaxb.XMLJavaTypeConverter.convertObjectValueToDataValue(XMLJavaTypeConverter.java:178) 在 org.eclipse.persistence.oxm.mappings.XMLDirectMapping.convertObjectValueToDataValue(XMLDirectMapping.java:511) 在 org.eclipse.persistence.oxm.mappings.XMLDirectMapping.getFieldValue(XMLDirectMapping.java:330) 在 org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue.marshalSingleValue(XMLDirectMappingNodeValue.java:62) 在 org.eclipse.persistence.internal.oxm.XMLDirectMappingNodeValue.marshal(XMLDirectMappingNodeValue.java:58) 在 org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:102) 在 org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:59) 在 org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:393) 在 org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:368) 在 org.eclipse.persistence.internal.oxm.XPathObjectBuilder.buildRow(XPathObjectBuilder.java:238) 在 org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:118) 在 org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:1) 在 org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:743) 在 org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:1124) 在 org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:869) ... 7 更多原因:异常 [EclipseLink-115] (Eclipse 持久性服务 - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DescriptorException

这似乎是moxy中的一个错误,因为我的适配器转换为非枚举类型,所以不应该有一个处理枚举的nestedConverter。

【问题讨论】:

    标签: jaxb marshalling moxy


    【解决方案1】:

    我设法用 2.5.0 重现了您的问题。这很可能是已经修复的错误。无法在 Eclipse Bugzilla 中找到错误,但相同的代码在 2.6.0 中可以正常工作。你能升级到最新的 MOXy 吗?

    【讨论】:

      猜你喜欢
      • 2015-09-04
      • 1970-01-01
      • 2011-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多