Sping Boot (Jackson2.13.3)中未调用自定义序列化程序

polkgigr  于 6个月前  发布在  其他
关注(0)|答案(1)|浏览(67)

我正在做一个使用Sping Boot 的REST API项目。每个REST API调用都应该以空字符串的形式返回NULL值,以便UI开发人员可以按原样显示这些值。
我找不到Jackson注解在序列化过程中将NULL转换为空字符串。因此,我编写了一个自定义序列化器,但它没有按预期工作。如果你看下面的代码,自定义序列化器中的sysout stmt,即“in date serializer”没有被打印。所以看起来自定义序列化器甚至没有被调用。
我用的是Jackson2.13.3.

@Entity
@Table(name="hlr_vw")
@Immutable
public class Healer_Flattened implements Serializable {
    
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "hlr_id")
    private Integer healerId;
    
    @JsonSerialize(using = CustomSerializer.class) 
    @com.fasterxml.jackson.annotation.JsonFormat(pattern="YYYY-MM-dd")
    @Column(name = "hlr_brth_dt")
    private Date dob;
    
    @JsonSerialize(using = CustomStringSerializer.class) 
    @Column(name = "hlr_rsdnc_city")
    private String city;
        
    // getters & setters 
}

字符串
REST控制器方法:

@GetMapping("/healers/search")
public List<Healer_Flattened> searchHealers(@Param("fname") String fname, @Param("city") String city, @Param("lngId") String lngId) throws JsonProcessingException {
        
    System.out.println("fname=" + fname);
    List<Healer_Flattened> hf = healerFlattenedRepo.findByFirstName(fname);
    System.out.println(hf.get(0).getFirstName());
    System.out.println("dob before serialization=" + hf.get(0).getDob());
    String serialized = new ObjectMapper().writeValueAsString(hf.get(0));
    System.out.println("After serialization=" + serialized);

    // ...
}


这是我的自定义序列化器:

public class CustomSerializer extends StdSerializer<Date> {
    
    private static final long serialVersionUID = 1L; 
    
    public CustomSerializer() {
        this(null);
    }
    
    public CustomSerializer(Class<Date> t) { 
        super(t); 
    } 
     
    @Override 
    public void serialize(Date value, JsonGenerator generator, SerializerProvider arg2) throws IOException { 
        System.out.println("in date serializer"); // doesn't print
        generator.writeStartObject();   
        generator.writeString(value==null?"":value.toString()); 
        generator.writeEndObject();
    } 
}


CustomStringSerializer类似。
日志输出:

2023-09-11 22:41:13.494 TRACE 17616 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [admin]


序列化后,我有:
{“healerId”:0,“dob”:null,“city”:null,“firstName”:“admin”,“lastName”:“admin”,“emailId”:“email protected(https://stackoverflow.com/cdn-cgi/l/email-protection)“,“acceptNewCaseFlag”:null,“maxNumberOfCases”:null,“languagesSpoken”:null}
如果你们中的任何人能帮助我,告诉我下面的代码有什么问题,我将不胜感激。

ttp71kqs

ttp71kqs1#

回答

对于自定义null-序列化,您应该使用nullsUsing属性:

@JsonSerialize(nullsUsing = CustomSerializer.class)

字符串
根据文档,这是你需要的:
序列化器类,用于序列化带注解的属性的空值,而不是默认的空值序列化器。请注意,在注解类型(类)时使用此属性目前没有效果(将来可能会改进)。自定义:2.3

定制序列化器

请注意,您不能在序列化程序中使用方法writeStartObject()writeEndObject()。这些方法用于编写{}来描述JSON对象。

关于另一种方法的几句话

使用应用程序逻辑实体作为域转移对象并不是一种常见的方法。我认为您应该将这些对象分开。
什么意思?
您的Healer_Flattened类是应用程序的私有实体。并且您希望通过REST API提供该类。这不是一个好主意,因为它会使您的应用程序变得不灵活,并且对REST API的消费者来说是危险的。
例如,如果您更改Healer_Flattened,REST API提供的数据将自动更改,而这些更改不会被预期到,或者您将不得不付出额外的努力,以避免使用@JsonIgnore或其他东西将您的内部更改提供给API消费者。
为了避免这些恼人的问题,通常使用DTO。

public class HealerFlattenedDto {
    private Integer healerId;
    private Date dob;
    private String city;
        
    // getters & setters 
}


与使用Healer_Flattened不同,您可以使用HealerFlattenedDto向API消费者提供数据。您可以根据需要更改此类。

相关问题