首页 > 解决方案 > 无法让 JsonIdentityInfo 正常工作

问题描述

我有两个对象之间的关系。我有一个 Spring CLI 与使用 Jackson 的 RESTful Web 服务进行通信。我正在使用 @JsonIdentityInfo 注释,但它无法在两个类之间创建关系。另外我正在使用 WebClient

第一个对象包含以下代码:

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(as= FuncUnit.class)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "fu_id", scope=FuncUnit.class)
@Setter @Getter 
public class FuncUnit  {

    @JsonProperty(value = "description")
    private String description;

    @Id @JsonProperty(value = "fu_id", required = true)
    private Long fu_id;

    // standard constructors    
    public FuncUnit (long fuId)
    {
        fu_id = fuId;
    }

    public FuncUnit() {}
}

第二个对象是:

@JsonSerialize(as=Engine.class)
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = Engine.class)
@Setter @Getter 
public class Engine  {

    @JsonProperty(value = "id", required = true)
    private Long id;

    @JsonProperty(value = "func_unit")
    private FuncUnit func_unit;

    public Engine() {}
}

现在我收到的json如下:

[
    {
        "id": 111,
        "functional_unit": {
            "description": "",
            "fu_id": 11,
        },
    },
    {
        "id": 112,
        "functional_unit": 11,
    }
]

而我写的webClient代码如下。(我也尝试过不使用 ExchangeStrategies,得到了相同的结果):

        ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
                .codecs(configurer ->
                        configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON)))
                .build();

        String url = cliUtils.getBaseUrl();
        WebClient webClient = WebClient.builder().exchangeStrategies(exchangeStrategies).build();
 
        UriComponentsBuilder builder = UriComponentsBuilder.newInstance().fromHttpUrl(url);

        List<Engine> units = webClient.get()
        .uri(builder.build().toUri())
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .retrieve()
        .bodyToFlux(Engine.class)
        .collectList()
        .block();

调用 webClient 代码时,我没有收到任何错误,但只有一个引擎具有 FuncUnit。另一个引擎包含一个 null 作为 FuncUnit。

标签: javaspringspring-bootjackson

解决方案


简短回答:改用 .bodyToMono(new ParameterizedTypeReference<List>(){}) 。

长答案:我确实遇到了一些问题。经过大量研究,没有一个解决方案对我有用。比如exchangeStrategy上的Customized ObjectMapper。

我们知道 JsonIdentityInfo 将第一个实例序列化为完整对象,将其他相同对象序列化为引用,以防止循环引用问题。

[
    {
        "id": 111,
        "functional_unit": {   // <----- First, Fully serialized
            "description": "",
            "fu_id": 11,
        },
    },
    {
        "id": 112,
        "functional_unit": 11,  // <----- Second, reference Id
    }
]

但是,这个问题不是因为序列化/反序列化,而是因为 Flux 的行为。尽管我们使用flux.collectList() 来获取所有列表项,但它们实际上是一一返回(非阻塞)并收集所有。第二个和后面的相同项目将无法看到第一个引用并注入引用。所以我尝试使用 Mono<List<>> 强制它们一起返回并且它起作用了。


推荐阅读