4

想象一下我有这样定义的枚举:

public enum ArchiveStatus implements Serializable {
  CANDIDATE         (0, "CANDIDATE", "Candidate for archival"),
  IN_LIBRARY          (1, "IN-LIBRARY", ".."),
  FROM_LIBRARY        (2, "FROM-LIBRARY", "..");

  private int id;
  private String shortName;
  private String longName;

  public ArchiveStatus( int id, String shortName, String longName ) {
    ..
  }

  public int getId() { .. }
  public String getShortName() { .. }
  public String getLongName() { .. }
}

默认情况下,MOXy 会将其序列化为 JSON,如下所示:

{
   ..
   "archiveStatus": "CANDIDATE",
   ..
}

有没有办法配置 MOXy(在映射文件中)以像常规类一样序列化枚举:

{
   ..
   "archiveStatus": { "id" : 0, "shortName": "CANDIDATE", "longName": "Candidate for archival" },
   ..
}
4

1 回答 1

4

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

ArchiveStatusAdapter

You can solve this use case by leveraging an XmlAdapter. XmlAdapter is a JAXB mechanism that allows you to marshal one type of object as another.

package forum10144489;

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

public class ArchiveStatusAdapter extends XmlAdapter<ArchiveStatusAdapter.AdaptedArchiveStatus, ArchiveStatus> {

    public static class AdaptedArchiveStatus {
        public int id;
        public String shortName;
        public String longName;
    }

    @Override
    public ArchiveStatus unmarshal(AdaptedArchiveStatus adaptedArchiveStatus) throws Exception {
        if(null == adaptedArchiveStatus) {
            return null;
        }
        return ArchiveStatus.valueOf(adaptedArchiveStatus.shortName);
    }

    @Override
    public AdaptedArchiveStatus marshal(ArchiveStatus archiveStatus) throws Exception {
        if(null == archiveStatus) {
            return null;
        }
        AdaptedArchiveStatus adaptedArchiveStatus = new AdaptedArchiveStatus();
        adaptedArchiveStatus.id = archiveStatus.getId();
        adaptedArchiveStatus.longName = archiveStatus.getLongName();
        adaptedArchiveStatus.shortName = archiveStatus.getShortName();
        return adaptedArchiveStatus;
    }

}

Root

The XmlAdapter can be specified at the field, property, type, or package level using the @XmlJavaTypeAdapter annotation.

package forum10144489;

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

public class Root {

    private ArchiveStatus archiveStatus;

    @XmlJavaTypeAdapter(ArchiveStatusAdapter.class)
    public ArchiveStatus getArchiveStatus() {
        return archiveStatus;
    }

    public void setArchiveStatus(ArchiveStatus archiveStatus) {
        this.archiveStatus = archiveStatus;
    }

}

jaxb.properties

To specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain classes with the following entry.

javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory

Demo

package forum10144489;

import java.io.StringReader;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>(2);
        properties.put("eclipselink.media-type", "application/json");
        properties.put("eclipselink.json.include-root", false);
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Root.class}, properties);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StringReader jsonStringReader = new StringReader("{\"archiveStatus\" : {\"id\" : 0, \"shortName\" : \"CANDIDATE\", \"longName\" : \"Candidate for archival\"}}");
        StreamSource jsonSource = new StreamSource(jsonStringReader);
        Root root = unmarshaller.unmarshal(jsonSource, Root.class).getValue();

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

Output

Below is the output from running the demo code:

{
   "archiveStatus" : {
      "id" : 0,
      "shortName" : "CANDIDATE",
      "longName" : "Candidate for archival"
   }
}

For More Information

于 2012-04-16T15:53:45.343 回答