我有一个对象的当前实现和一个使用 Jersey/JAX-RS 的 REST API。
对象/Bean:
@XmlRootElement(name = "MyEntry")
@XmlType(propOrder = {"key", "value"})
public class MyEntry {
private String key;
private String value;
public MyEntry() {
}
public MyEntry(String key, String value) {
this.key = key;
this.value = value;
}
@XmlElement
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@XmlElement
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
现在有一个更高级别的对象,这将是我的最终回应。
public class MyResponse {
protected String id;
protected String department;
protected List<MyEntry> myEntries;
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public List<MyEntry> getMyEntries() {
return myEntries;
}
public void setMyEntry(List<MyEntry> myEntries) {
this.myEntries = myEntries;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
我的 API 调用如下:
@GET
@Path(/v1/myresource)
public MyResponse getMyResource(...... list of parameters ....) {}
现在输出如下所示
{
id: "myid",
department: "mydepartment",
myentries: [
{
key: "key1",
value: "value1"
},
{
key: "key2",
value: "value2"
},
{
key: "key3",
value: "value3"
}
]
}
但是,我正在尝试获得如下输出:
{
id: "myid",
department: "mydepartment",
myentries: [
key1: "value1"
key2: "value2"
key3: "value3"
]
}
任何建议都会非常有帮助。
====更新==== 添加 XmlAdapter 的建议后,一切正常。但是,还有一件事是 - 我还有另一个地方必须使用 ObjectMapper 将输入请求反序列化到 Department 类中
private MyResponse createResponse(String requestBody...) throws Exception {
ObjectMapper mapper = new ObjectMapper();
MyResponse response = null;
try {
response = mapper.readValue(requestBody, MyResponse.class);
} catch (Exception ex) {
//
}
}
我收到这个错误 无法从 [Source: java.io.StringReader@20fcc207; 的 START_OBJECT token\中反序列化 java.util.ArrayList 的实例;行:8,列:37](通过引用链:com.apigee.apimodel.repo.persistence.beans.MyResponse[\"myEntries\"]
有没有办法配置 ObjectMapper 在将值读入对象时识别 @XmlJavaTypeAdapter(MyEntryAdapter.class)?
最佳答案
首先,这不是有效的 JSON
myentries: [
key1: "value1"
key2: "value2"
key3: "value3"
]
键/值需要包含在 s JSON 对象中
myentries: {
key1: "value1"
key2: "value2"
key3: "value3"
}
也就是说,可以将其转换为 Java Map
.但是你想要一个 List<MyEntry>
. 为此,我们可以使用 XmlAdapter
转换 Map<String, String>
至 List<MyEntry>
.会是这样的
public class MyEntryAdapter extends XmlAdapter<HashMap<String, String>, List<MyEntry>> {
@Override
public List<MyEntry> unmarshal(HashMap<String, String> map) throws Exception {
List<MyEntry> entries = new ArrayList<>();
for (Map.Entry<String, String> entry: map.entrySet()) {
MyEntry myEntry = new MyEntry();
myEntry.setKey(entry.getKey());
myEntry.setValue(entry.getValue());
entries.add(myEntry);
}
return entries;
}
@Override
public HashMap<String, String> marshal(List<MyEntry> entries) throws Exception {
HashMap<String, String> map = new HashMap<>();
for (MyEntry entry: entries) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
}
然后我们只注释myEntries
属性为 @XmlJavaTypeAdapter
@XmlRootElement
public class MyResponse {
...
protected List<MyEntry> myEntries;
...
@XmlJavaTypeAdapter(MyEntryAdapter.class)
public List<MyEntry> getMyEntries() {
return myEntries;
}
...
}
这是一个使用 GET 和 POST 进行测试的示例
资源类
@Path("/test")
public class TestResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getResponse() {
MyResponse response = new MyResponse();
response.setId("1");
response.setDepartment("Hard Knocks");
List<MyEntry> entries = new ArrayList<>();
MyEntry entry = new MyEntry();
entry.setKey("key1");
entry.setValue("value1");
entries.add(entry);
entry = new MyEntry();
entry.setKey("key2");
entry.setValue("valu2");
entries.add(entry);
response.setMyEntry(entries);
return Response.ok(response).build();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response post(MyResponse response) {
System.out.println("id: " + response.getId());
System.out.println("Department: " + response.getDepartment());
System.out.println("MyEntrys: ");
for (MyEntry entry : response.getMyEntries()) {
System.out.println(entry);
}
return Response.ok().build();
}
}
测试用例
@Test
public void testGetIt() throws Exception {
target = target.path("test");
Response response = target.request().accept(MediaType.APPLICATION_JSON).get();
String jsonResponse = response.readEntity(String.class);
System.out.println(jsonResponse);
String jsonPost = "{\n"
+ " \"department\": \"Hard Knocks\",\n"
+ " \"id\": \"1\",\n"
+ " \"myEntries\": {\n"
+ " \"key1\": \"value1\",\n"
+ " \"key2\": \"valu2\"\n"
+ " }\n"
+ "}";
response = target.request().post(Entity.json(jsonPost));
response.close();
}
GET 的结果
{
"id": "1",
"department": "Hard Knocks",
"myEntries": {
"key1": "value1",
"key2": "valu2"
}
}
POST 的结果(覆盖 MyEntry 中的 toString)
id: 1
Department: Hard Knocks
MyEntrys:
MyEntry{key=key1, value=value1}
MyEntry{key=key2, value=valu2}
注意事项:
我测试了两个不同的供应商。给出上述结果的是
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.13</version>
</dependency>
我也尝试过使用 MOXy 提供程序
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.13</version>
</dependency>
但这是我得到的结果(使用 GET 将 Map 打印为字符串,并且 POST 返回 0 MyEntrys)
{
"department": "Hard Knocks",
"id": "1",
"myEntries": "{key1=value1, key2=valu2}"
}
不确定为什么 MOXy 在这种情况下不起作用。
关于java - 使用 jersy/JAX-RS REST 自定义对象的响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26793672/