Java jax-rs 客户端响应实体通用
Java jax-rs client response entity generic
我对通用函数有疑问。我想使用一个函数,我为其分配了某个 class / 类型,首先从休息响应生成相应的结果,然后 return 它。
public class TimerService {
[...]
public <T extends myObjInterface> RestMessageContainer<T> send(String endpointPath, Map<String, String> parameters, Class<T> clazz) {
[...]
Response response = webTarget.request(MediaType.APPLICATION_JSON_TYPE).get();
RestMessageContainer<T> container = response.readEntity(new GenericType<RestMessageContainer<T>>() {});
return container;
}
}
public class RestMessageContainer<T extends myObjInterface> {
[...]
@XmlAttribute(name = "data")
private List<T> data;
[...]
}
我在运行时收到以下错误消息。
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.test.myObjInterface` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
14:47:41,982 ERROR [stderr] (EJB default - 2) at [Source: (org.jboss.resteasy.client.jaxrs.internal.ClientResponse$InputStreamWrapper); line: 3, column: 14] (through reference chain: com.test.RestMessageContainer["data"]->java.util.ArrayList[0])
第RestMessageContainer<T> container = response.readEntity(new GenericType<RestMessageContainer<T>>() {});
行输出错误
我的方法是否完全正确或者我应该如何解决我的问题?
您不能创建抽象的实例 class。不过,你可以通过一个简单的注解来解决问题——@JsonDeserialize
on the abstract class:
@JsonDeserialize(as = Cat.class)
abstract class Animal {...}
在您的情况下,摘要 class 将是 myObjInterface
。
注意:如果您有多个子类型的摘要 class,那么您应该考虑包含子类型信息,如此 post.
感谢您的建议,
我有几个子类。 JSON 字符串中没有关于类型的信息。该类型来自请求地址。我无法配置 Jackson 来识别子类型。 JSON 字符串中没有可用作类型的唯一字段。
我无法更改提供 JSON 字符串的 Web 服务。
[更新]
我找到了解决办法。我不再让 JAX-RS 客户端转换 JSON 字符串。我将 JSON 字符串作为字符串返回给我,并使用 Jackson 独立转换它。
public <T extends myObjInterface> RestMessageContainer<T> send(String endpointPath, Map<String, String> parameters, Class<T> clazz) {
[...]
Response response = webTarget.request(MediaType.APPLICATION_JSON_TYPE).get();
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
RestMessageContainer<T> container = mapper.readValue(response.readEntity(String.class), mapper.getTypeFactory().constructParametricType(RestMessageContainer.class, clazz));
return container;
}
我对通用函数有疑问。我想使用一个函数,我为其分配了某个 class / 类型,首先从休息响应生成相应的结果,然后 return 它。
public class TimerService {
[...]
public <T extends myObjInterface> RestMessageContainer<T> send(String endpointPath, Map<String, String> parameters, Class<T> clazz) {
[...]
Response response = webTarget.request(MediaType.APPLICATION_JSON_TYPE).get();
RestMessageContainer<T> container = response.readEntity(new GenericType<RestMessageContainer<T>>() {});
return container;
}
}
public class RestMessageContainer<T extends myObjInterface> {
[...]
@XmlAttribute(name = "data")
private List<T> data;
[...]
}
我在运行时收到以下错误消息。
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.test.myObjInterface` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
14:47:41,982 ERROR [stderr] (EJB default - 2) at [Source: (org.jboss.resteasy.client.jaxrs.internal.ClientResponse$InputStreamWrapper); line: 3, column: 14] (through reference chain: com.test.RestMessageContainer["data"]->java.util.ArrayList[0])
第RestMessageContainer<T> container = response.readEntity(new GenericType<RestMessageContainer<T>>() {});
我的方法是否完全正确或者我应该如何解决我的问题?
您不能创建抽象的实例 class。不过,你可以通过一个简单的注解来解决问题——@JsonDeserialize
on the abstract class:
@JsonDeserialize(as = Cat.class)
abstract class Animal {...}
在您的情况下,摘要 class 将是 myObjInterface
。
注意:如果您有多个子类型的摘要 class,那么您应该考虑包含子类型信息,如此 post.
感谢您的建议, 我有几个子类。 JSON 字符串中没有关于类型的信息。该类型来自请求地址。我无法配置 Jackson 来识别子类型。 JSON 字符串中没有可用作类型的唯一字段。 我无法更改提供 JSON 字符串的 Web 服务。
[更新]
我找到了解决办法。我不再让 JAX-RS 客户端转换 JSON 字符串。我将 JSON 字符串作为字符串返回给我,并使用 Jackson 独立转换它。
public <T extends myObjInterface> RestMessageContainer<T> send(String endpointPath, Map<String, String> parameters, Class<T> clazz) {
[...]
Response response = webTarget.request(MediaType.APPLICATION_JSON_TYPE).get();
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
RestMessageContainer<T> container = mapper.readValue(response.readEntity(String.class), mapper.getTypeFactory().constructParametricType(RestMessageContainer.class, clazz));
return container;
}