如何使用Jackson来指定某些要序列化为JSON的字段?

时间:2019-06-21 22:16:09

标签: java json jackson

我有Athlete和Injury两个类,最后一个包含Athlete对象,当发生序列化时,我得到以下JSON表示形式: {"id":X,"kindOfInjury":"...","muscle":"...","side":"...","outOfTrainig":Y,"injuryDate":"2018-Jun-02","athlete":{"id":X,"firstName":"...","lastName":"...","age":X,"email":"..."}}

我不想获取有关运动员的所有信息-仅获取"athleteId":1之类的id值,而不是获取整个对象的表示形式。

因此,我发现我需要应用我的自定义序列化程序,该序列化程序在Injury类上实现StdSerializer。所以这就是我到目前为止所得到的:

class InjurySerializer extends StdSerializer<Injury> {

    public InjurySerializer() {
        this(null);
    }

    public InjurySerializer(Class<Injury> i) {
        super(i);
    }

    @Override
    public void serialize(
            Injury value, JsonGenerator jgen, SerializerProvider provider)
            throws IOException, JsonProcessingException {

        jgen.writeStartObject();
        jgen.writeNumberField("id", value.getId());
        jgen.writeStringField("kindOfInjury", value.getKindOfInjury());
        jgen.writeStringField("muscle", value.getMuscle());
        jgen.writeStringField("side", value.getSide());
        jgen.writeNumberField("outOfTraining", value.getOutOfTraining());
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MMM-dd");
        Date date = new Date();
        String ourformat = formatter.format(date.getTime());
        jgen.writeStringField("injuryDate", ourformat);
        jgen.writeNumberField("athleteId", value.getAthlete().getId());
        jgen.writeEndObject();
    }
}

以及实际的伤害类别:

@Entity
@Table(name = "INJURY")
@JsonSerialize(using = InjurySerializer.class)
public class Injury {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "INJURY_ID")
    private Long id;

    @Column(name = "KIND_OF_INJURY")
    private String kindOfInjury;

    @Column(name = "MUSCLE")
    private String muscle;

    @Column(name = "SIDE")
    private String side;

    @Column(name = "OUT_OF_TRAINING")
    private Integer outOfTraining;

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MMM-dd")
    @Column(name = "INJURY_DATE")
    private Date injuryDate;

    @ManyToOne
    @JoinColumn(name = "ATHLETE_ID")
    private Athlete athlete;

因此,此解决方案有效,但看起来很糟糕...

问题如下: 1)是否有任何机制为我提供了仅更改我真正需要的ONE属性的序列化的功能,而不是编写所有繁琐的代码(实际更改仅在此行中)? :

jgen.writeNumberField("athleteId", value.getAthlete().getId());

2)您能推荐我一些有关杰克逊的文章,因为在这一点上我对此有些困惑吗?

感谢您的耐心配合,我们期待您的答复:)

3 个答案:

答案 0 :(得分:1)

您可能会发现使用@JsonIgnore注释而不是编写自定义序列化程序会比较麻烦。举个例子

public class Person {

  private int id;

  @JsonIgnore
  private String first;

  @JsonIgnore
  private String last;

  @JsonIgnore
  private int age;

  // getters and setters omitted
}

Jackson序列化此类时,它仅在结果JSON中包含“ id”属性。

  @Test
  void serialize_only_includes_id() throws JsonProcessingException {
    final var person = new Person();
    person.setId(1);
    person.setFirst("John");
    person.setLast("Smith");
    person.setAge(22);

    final var mapper = new ObjectMapper();
    final var json = mapper.writeValueAsString(person);
    assertEquals("{\"id\":1}", json);
  }

答案 1 :(得分:1)

您可以为此目的使用数据传输对象(DTO)。

像这样创建一个简单的POJO:

public class InjuryDTO {

  //all other required fields from Injury model...

  @JsonProperty("athlete_id")
  private Long athleteId;
}

并为其转换:

@Component
public class InjuryToDTOConverter{

  public InjuryDTO convert(Injury source){
    InjuryDTO target = new InjuryDTO();
    BeanUtils.copyProperties(source, target); //it will copy fields with the same names
    target.setAthleteId(source.getAthlete().getId());
    return target;
  }
}

您可以这样使用它:

@RestController("/injuries")
public class InjuryController {

  @Autowired
  private InjuryToDTOConverter converter;

  @Autowired
  private InjuryService injuryService;

  @GetMapping
  public InjuryDTO getInjury(){
    Injury injury = injuryService.getInjury();
    return converter.convert(injury);
  }
}

此方法的好处是您可以具有多个用于不同目的的DTO。

答案 2 :(得分:0)

您可以尝试使用基本的字符串替换方法来处理json字符串。 我运行了您的json并将其转换为所需的格式:

public static void main(String args[]) {
    String json = "{\"id\":123,\"kindOfInjury\":\"...\",\"muscle\":\"...\",\"side\":\"...\",\"outOfTrainig\":Y,\"injuryDate\":\"2018-Jun-02\",\"athlete\":{\"id\":456,\"firstName\":\"...\",\"lastName\":\"...\",\"age\":14,\"email\":\"...\"}}";
    JsonObject injury = new JsonParser().parse(json).getAsJsonObject();
    JsonObject athelete = new JsonParser().parse(injury.get("athlete").toString()).getAsJsonObject();
    String updateJson = injury.toString().replace(injury.get("athlete").toString(), athelete.get("id").toString());
    updateJson = updateJson.replace("athlete", "athleteId");
    System.out.println(updateJson);
}

输出:

{"id":123,"kindOfInjury":"...","muscle":"...","side":"...","outOfTrainig":"Y","injuryDate":"2018-Jun-02","athleteId":456}

依赖性:

implementation 'com.google.code.gson:gson:2.8.5'

如果您可以用正则表达式替换,它将更加整洁。