使用 Gson/Jackson 和 Spring Boot 重新创建没有字段属性的 DTO 类,而不是使其为空

Posted

技术标签:

【中文标题】使用 Gson/Jackson 和 Spring Boot 重新创建没有字段属性的 DTO 类,而不是使其为空【英文标题】:Recreate DTO class without field property instead of having it null using Gson/Jackson and Spring Boot 【发布时间】:2021-01-08 08:47:36 【问题描述】:

我有一个返回这个的 DTO 类:


  "id": "fdbfb1ec-1f1e-4867-9cc8-73929fbcc07e",
  "title": "My another category",
  "reports": null

当我实际上希望我的一些 api 调用按照下面的方法将报告键作为它的一部分而不是设置为 null 时。


  "id": "fdbfb1ec-1f1e-4867-9cc8-73929fbcc07e",
  "title": "My another category",

我尝试使用 Gson 和 Expose 注释,相信这会删除我的密钥,但它似乎只是将其变为 null。我尝试使用 @Expose(serialize = false, deserialize = false) 或不使用注释,因为我的 Gson 对象使用 excludeFieldsWithoutExposeAnnotation() 片段,但两者都给了我相同的结果。但是,我可以看到我的字符串转换器排除了报告键并给了我这个"id":"fdbfb1ec-1f1e-4867-9cc8-73929fbcc07e","title":"My another category" 但不确定为什么在重新创建对象时该属性仍然存在,以及这种情况的唯一解决方案是否不是通过 Gson 而是有两个完整的而是使用不同的 DTO,一个具有该属性,另一个不具有该属性?

@AllArgsConstructor
@NoArgsConstructor
@Data
public class CategoryQueryDto 

    @Expose()
    private UUID id;
    @Expose()
    private String title;

    @Expose(serialize = false, deserialize = false)
    private List<ReportQueryDto> reports;

    public CategoryQueryDto(String title) 
        this.title = title;
    

    public CategoryQueryDto(UUID id, String title) 
        this.id = id;
        this.title = title;
    




@Override
public CategoryQueryDto getCategory(UUID id) 

    if (categoryRepository.findById(id).isPresent()) 
        Category category = categoryRepository.findById(id).get();

        CategoryQueryDto categoryQueryDto = new CategoryQueryDto(category.getId(), category.getTitle());

        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        String converter = gson.toJson(categoryQueryDto);

        categoryQueryDto = gson.fromJson(converter, CategoryQueryDto.class);


        return categoryQueryDto;
     else 
        return null;
    


非常感谢。

更新

这是我在 Github 上的代码https://github.com/francislainy/gatling_tool_backend

尝试使用 Jackson 而不是 Gson,但遇到了同样的问题。

【问题讨论】:

这听起来很奇怪,尤其是因为 Gson 默认情况下甚至不应该序列化 null 字段(请参阅 GsonBuilder.serializeNulls())。会不会是 Lombok(您显然正在使用其注释)以某种方式干扰 Gson?当您删除注释(用于测试)时会发生什么?还有你的getCategory(...) 方法的目的是什么?看起来它正在序列化,然后立即再次反序列化对象。 嗨@Marcono1234,感谢您的评论。我现在尝试从我的项目中删除所有 lombok 并执行普通的构造函数、getter 和 setter,但恐怕我得到了相同的结果。这是我在 Github 上的代码,如果您或其他人可以查看并指出我可能做错了什么。我是 Spring 的新手,不太确定还能尝试什么。 github.com/francislainy/gatling_tool_backend Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); String converter = gson.toJson(categoryQueryDto); categoryQueryDto = gson.fromJson(converter, CategoryQueryDto.class); 关于你的问题,这是你指的部分吗?是的,那是我尝试 json 然后强行通过 gson 回到类对象,看看这是否可行。 我不熟悉 Spring 框架,所以下面的内容可能完全错误,但也许它仍然有帮助。看来 Spring Boot 默认使用 Jackson 进行 JSON 序列化。所以你要么必须configure Jackson要么specify that Gson is used。 【参考方案1】:

在我想显示的字段上使用@JsonInclude(JsonInclude.Include.NON_NULL),如果它不为空并且它有效。

@AllArgsConstructor
@NoArgsConstructor
@Data
public class CategoryQueryDto 

@Expose()
private UUID id;
@Expose()
private String title;

@JsonInclude(JsonInclude.Include.NON_NULL)
private List<ReportQueryDto> reports = null;

public CategoryQueryDto(String title) 
    this.title = title;


public CategoryQueryDto(UUID id, String title) 
    this.id = id;
    this.title = title;



这里是我和杰克逊的控制器

@Service
public class CategoryQueryServiceImpl implements CategoryQueryService 

@Autowired
private CategoryRepository categoryRepository;

@Autowired
private ReportRepository reportRepository;

ObjectMapper mapper = new ObjectMapper();

@Override
public CategoryQueryDto getCategory(UUID id) throws JsonProcessingException 

    if (categoryRepository.findById(id).isPresent()) 
        Category category = categoryRepository.findById(id).get();

        CategoryQueryDto categoryQueryDto = new CategoryQueryDto(category.getId(), category.getTitle());

        
        String converter = mapper.writeValueAsString(categoryQueryDto);

        categoryQueryDto = mapper.readValue(converter, CategoryQueryDto.class);


        return categoryQueryDto;


     else 
        return null;
    


POM

<dependency>
     <groupId>org.codehaus.jackson</groupId>
     <artifactId>jackson-core-asl</artifactId>
     <version>1.9.13</version>
     <scope>test</scope>
</dependency>

【讨论】:

在此解决方案的 Gson 等效问题***.com/questions/64105969/…

以上是关于使用 Gson/Jackson 和 Spring Boot 重新创建没有字段属性的 DTO 类,而不是使其为空的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot与Jackson ObjectMapper

json解析性能比较(gson与jackson) (zz)

Gson/Jackson/FastJson工具类

Json 工具介绍 fastjson gson jackson

JSON工具类(FastJson,Gson,Jackson)

改造 2 和 Spring RestController