【问题标题】:How to write a JsonStructure (JSR-353) XmlAdaptor for JAXB MOXy?如何为 JAXB MOXy 编写 JsonStructure (JSR-353) XmlAdaptor?
【发布时间】:2015-02-24 17:58:05
【问题描述】:

我需要将一些任意 JSON 内容包装到 POJO 中,然后使用 MOXy/JAXB 将其序列化为 JSON,但无法弄清楚如何将 JsonObject 与 JAXB 绑定。我只需要编组JsonObject,不需要解组。

即拥有 POJO:

@XmlRootElement
public class MsgPOJO {
  public String type;
  public Object content;
}

如何将任意 JSON 内容放入 'MsgPOJO.content' 中,并对其进行序列化:

String jsonDoc = "{\"prop\":\"value\"}";
MsgPOJO msg = new MsgPOJO();
msg.type = "whatever";
msg.content = jsonDoc;

所以这将是输出:

{
  "type": "whatever",
  "content": {
    "prop": "value"
   }
}

我正在考虑用@XmlJavaTypeAdapter 注释MsgPOJO.content,但这似乎没有让我得到任何结果,因为JSON 内容可能是任意的。

如果 moxy 可以编组 JsonObjectJsonStructure 那就太好了,所以我可以像这样定义 POJO:

@XmlRootElement
public class MsgPOJO {
  public String type;
  public JsonObject content;
}

有没有办法让它工作?还是 MOXy/JAXB 的限制?

【问题讨论】:

标签: java json jaxb moxy jsr-353


【解决方案1】:

MOXy 默认不支持 JSON-P 结构的编组/解组,需要实现 XmlJavaTypeAdapter。下面是 JsonObject 适配器的示例。

MsgPOJO.java

package org.eclipse.persistence.testing.jsonp;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * Created by mvojtek on 24/02/15.
 */
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MsgPOJO {

    public String type;

    public JsonObjectWrapper content;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public JsonObjectWrapper getContent() {
        return content;
    }

    public void setContent(JsonObjectWrapper content) {
        this.content = content;
    }

    @Override
    public String toString() {
        return "MsgPOJO{" +
                "type='" + type + '\'' +
                ", content=" + content +
                '}';
    }
}

JsonObjectWrapper.java

package org.eclipse.persistence.testing.jsonp;

import javax.json.JsonObject;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

/**
 * Created by mvojtek on 24/02/15.
 */
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class JsonObjectWrapper {

    @XmlJavaTypeAdapter(JsonObjectAdapter.class)
    private JsonObject jsonObject;

    public JsonObject getJsonObject() {
        return jsonObject;
    }

    public void setJsonObject(JsonObject jsonObject) {
        this.jsonObject = jsonObject;
    }

    @Override
    public String toString() {
        return "JsonObjectWrapper{" +
                "jsonObject=" + jsonObject +
                '}';
    }
}

JsonObjectAdapter.java

package org.eclipse.persistence.testing.jsonp;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.io.StringReader;

/**
 * Created by mvojtek on 24/02/15.
 */
public final class JsonObjectAdapter extends XmlAdapter<String,JsonObject> {
    @Override
    public String marshal(JsonObject v) throws Exception {
        if (null == v) {
            return null;
        }
        return v.toString();
    }

    @Override
    public JsonObject unmarshal(String v) throws Exception {
        if (null == v) {
            return null;
        }
        JsonReader jsonReader = Json.createReader(new StringReader(v));
        return jsonReader.readObject();
    }
}

Test.java

package org.eclipse.persistence.testing.jsonp;

import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.oxm.MediaType;

import javax.json.Json;
import javax.json.JsonReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;

public class Test {

    public static void main(String[] args) throws Exception {

        //marshal
        JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[]{MsgPOJO.class}, null);

        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);

        MsgPOJO msgPOJO = new MsgPOJO();
        msgPOJO.setType("myType");

        JsonReader jsonReader = Json.createReader(new StringReader("{\"prop\":\"value\"}"));

        JsonObjectWrapper wrapper = new JsonObjectWrapper();
        wrapper.setJsonObject(jsonReader.readObject());

        msgPOJO.setContent(wrapper);

        StringWriter marshallerOutput = new StringWriter();

        marshaller.marshal(msgPOJO, marshallerOutput);

        String result = marshallerOutput.toString();
        System.out.println("marshal result = "+result);

        //unmarshal
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setProperty(JAXBContextProperties.MEDIA_TYPE, MediaType.APPLICATION_JSON);
        unmarshaller.setProperty(JAXBContextProperties.JSON_INCLUDE_ROOT, true);

        MsgPOJO msgPOJO2 = (MsgPOJO)unmarshaller.unmarshal(new StringReader(result));

        System.out.println("msgPOJO2="+msgPOJO2);
    }
}

如果你不想要字符串,你可以借助 MyList 和 MyMap 结构来编写通用结构。之后,您可以编写 XmlJavaTypeAdapter,它将 JsonObject 编组为这个新类型。结果将是 json,与输入的字符串表示并不完全一样,而是合法的 json。

https://github.com/eclipse/eclipselink.runtime/blob/master/moxy/eclipselink.moxy.test/src/org/eclipse/persistence/testing/jaxb/rs/model/MyList.java

https://github.com/eclipse/eclipselink.runtime/blob/master/moxy/eclipselink.moxy.test/src/org/eclipse/persistence/testing/jaxb/rs/model/MyMap.java

【讨论】:

  • @mvojtek:谢谢你的回答,这与我尝试的类似 - 问题在于它被编组为:{"msgPOJO":{"type":"myType","content":{"jsonObject":"{\"prop\":\"value\"}"}}} 而不是:{"msgPOJO":{"type":"myType","content":{"jsonObject":{"prop":"value"}}}},即@987654329 @ 只是调用 JsonObject.toString(),所以 content.jsonObject 被序列化为字符串而不是 JSON 对象/映射。
  • 我已经更新了我的答案,其中包含一些关于没有字符串结果的适配器的提示。
  • 如果您有列表映射或映射映射,它仍然不起作用,即它仅适用于简单的字符串到字符串对象或字符串数​​组。我需要的是一种在 JAXB/MOXy POJO 中传递通用 JSON 对象的方法。
  • 如果您为此构建通用结构,它应该可以工作。类似于 GeneralStructure { MyList myList; MyMap myMap; String terminal;} 这不是很好,但应该可以工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
  • 2012-04-18
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多