如何解决Spring HATEOAS客户端忽略空链接-“模板不能为空或为空!”例外
我正在访问由第三方提供的HATEOAS API,由于某种原因,我们从他们那里收到的响应包含具有href的空值的链接。这引发了异常。我无法控制此API,因此无法更改响应。有什么办法可以解决这个问题?
以下是JSON的示例:
{
"_embedded": {
"example": [{ ... }]
}
"_links": {
"next": {
"href": null
},"prev": {
"href": null
},"self": {
"href": "https://bag.basisregistraties.overheid.nl/api/v1/panden"
}
}
}
当我使用RestTemplate发出请求时,我收到一个IllegalArgumentException消息,消息为“ Template不能为null或为空!”
Caused by: java.lang.IllegalArgumentException: Template must not be null or empty!
at org.springframework.util.Assert.hasText(Assert.java:284)
at org.springframework.hateoas.UriTemplate.<init>(UriTemplate.java:56)
at org.springframework.hateoas.Link.<init>(Link.java:94)
at org.springframework.hateoas.hal.Jackson2HalModule$HalLinkListDeserializer.deserialize(Jackson2HalModule.java:583)
at org.springframework.hateoas.hal.Jackson2HalModule$HalLinkListDeserializer.deserialize(Jackson2HalModule.java:528)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:136)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializefromObject(BeanDeserializer.java:369)
我尝试在本地提供此JSON,以便可以从中删除下一个和上一个链接,并且效果很好。我查看了一下代码,但失败了,因为它试图执行new UriTemplate(href)
,它不接受null作为参数。
我们正在运行Spring Boot版本2.1.8.RELEASE
和spring-hateoas版本0.25.2
。下面是发出请求的代码:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNowN_PROPERTIES,false);
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION,false);
Jackson2HalModule jackson2HalModule = new Jackson2HalModule();
mapper.registerModule(jackson2HalModule);
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(MediaType.parseMediaTypes(Arrays.asList("application/json;charset=UTF-8","application/hal+json")));
converter.setobjectMapper(mapper);
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
RestTemplate restTemplate = restTemplateBuilder.messageConverters(Collections.singletonList(converter)).build();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept","application/json,application/*+json");
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
httpentity<String> entity = new httpentity(entity.toString(),headers);
ParameterizedTypeReference<Resources<Panden>> typeRefDevices = new ParameterizedTypeReference<>() {};
ResponseEntity<Resources<Panden>> result = restTemplate.exchange(endpoint,HttpMethod.POST,entity,typeRefDevices);;
解决方法
花了一些时间查看Jackson2HalModule的代码后,我找到了解决此问题的方法。没有可用于告诉库仅忽略具有空值的链接的配置。我可以做的是重写deserialize()方法,以便我可以添加一个空检查并避免该问题。
为了执行此操作,我必须创建新的链接反序列化器类。它需要扩展 Jackson2HalModule.HalLinkListDeserializer ,然后我只是复制并粘贴了我想要的修改从库源代码。
public class CustomHalLinkListDeserializer extends Jackson2HalModule.HalLinkListDeserializer {
@Override
public List<Link> deserialize(JsonParser jp,DeserializationContext ctxt)
throws IOException,JsonProcessingException {
List<Link> result = new ArrayList<Link>();
String relation;
// links is an object,so we parse till we find its end.
while (!JsonToken.END_OBJECT.equals(jp.nextToken())) {
if (!JsonToken.FIELD_NAME.equals(jp.getCurrentToken())) {
throw new JsonParseException(jp,"Expected relation name",jp.getCurrentLocation());
}
// save the relation in case the link does not contain it
relation = jp.getText();
if (JsonToken.START_ARRAY.equals(jp.nextToken())) {
while (!JsonToken.END_ARRAY.equals(jp.nextToken())) {
CustomLink link = jp.readValueAs(CustomLink.class);
String href = link.getHref() != null ? link.getHref() : "http://dummy";
result.add(new Link(href,relation));
}
} else {
CustomLink link = jp.readValueAs(CustomLink.class);
String href = link.getHref() != null ? link.getHref() : "http://dummy";
result.add(new Link(href,relation));
}
}
return result;
}
}
然后,为了告诉Jackson2HalModule使用新类,我必须创建自己的MixInAnnotation类,在该类中,我指定使用 CustomHalLinkListDeserializer
反序列化链接public abstract class CustomResourceSupportMixin extends ResourceSupport {
@Override
@XmlElement(name = "link")
@JsonProperty("_links")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonSerialize(using = Jackson2HalModule.HalLinkListSerializer.class)
@JsonDeserialize(using = CustomHalLinkListDeserializer.class)
public abstract List<Link> getLinks();
}
可以在按如下方式配置jackson2HalModule时设置新的MixInAnnotation
ObjectMapper mapper = new ObjectMapper();
Jackson2HalModule jackson2HalModule = new Jackson2HalModule();
jackson2HalModule.setMixInAnnotation(ResourceSupport.class,CustomResourceSupportMixin.class);
mapper.registerModule(jackson2HalModule);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。