Jackson 自訂 Serialize & Deserialize

蔡維宇 2019/12/31 11:54:30
1661

 

首先建立一組 REST API 功能是對UserCRUD操作

  1. 實作Deserialization

package com.skbank.rest.resource;

import com.skbank.rest.entity.Message;
import com.skbank.rest.entity.User;
import com.skbank.rest.exception.UserNotFoundException;
import com.skbank.rest.service.UserDAOService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.validation.Valid;
import java.net.URI;
import java.util.List;

@RestController
public class UserResource {

    @Autowired
    private UserDAOService service;

    // GET /users
    // retreive all users
    @GetMapping("/users")
    public List<User> retrieveAllUsers() {
        return service.findAll();
    }

    // GET /users/{id}
    @GetMapping("/users/{id}")
    public User retreiveUser(@PathVariable int id) {
        User user = service.findOne(id);
        if (user == null) {
            throw new UserNotFoundException("id-" + id);
        }
        return user;
    }


    @PostMapping("/users")
    public ResponseEntity<Message> createUser(@Valid @RequestBody User user) {
        User savedUser = service.save(user);

        // CREATED
        // /user/{id} savedUser.getId();
        URI location = ServletUriComponentsBuilder.fromCurrentRequest()
                .path("/{id}").buildAndExpand(savedUser.getId()).toUri();

        return ResponseEntity.created(location).build();
    }

    @DeleteMapping("/users/{id}")
    public void deleteUser(@PathVariable int id) {
        User user = service.deleteById(id);
        if (user == null) {
            throw new UserNotFoundException("id-" + id);
        }

    }
}

當新增User時所帶入的birthDateString時,Jackson無法將值與User.birthDate綁定,進行deserialize 時會發生Unparseable date 的問題

實作Desialize 時需要繼承 JsonDeserializer   並實作  deseriaize() , 如下圖:

package com.skbank.rest.util.jackson;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.skbank.rest.entity.User;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class UserCustomDeserializer extends JsonDeserializer<User> {

    public UserCustomDeserializer() {
    }

    @Override
    public User deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {

        JsonNode jsonNode = jp.getCodec().readTree(jp);

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String birthDateStr = jsonNode.get("birthDate").asText();
        String username = jsonNode.get("name").asText();
        Date birthDate = null;
        try {
            birthDate = sdf.parse(birthDateStr);
        } catch (ParseException e) {
            System.out.println(e.getMessage());
        }
        return new User(null, username, birthDate);
    }
}

 

完成後續在User.java 內加入

@JsonDeserialize(using = UserCustomDeserializer.class)

 

使得deserialize實作生效,這時再新增一個User,得到 HttpStatus 201 

呼叫查詢全部User得到剛才新增的User資料已新增成功

2.實作Serialization

由以上可發現POJO User裡的命名與回傳的Json欄位對應到相同的值,在實際應用上我們通常不會直接將一樣的POJO欄位名稱回傳,這時就需要實作Serialization,
我們需要繼承讓實作類繼承JsonSerializer並實作Serialize()

package com.skbank.rest.util.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.skbank.rest.entity.User;

import java.io.IOException;

public class UserCustomSerializer extends JsonSerializer<User> {

    public UserCustomSerializer() {
    }

    @Override
    public void serialize(User value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeNumberField("userid", value.getId());
        gen.writeStringField("username", value.getName());
        gen.writeObjectField("birthDate", value.getBirthDate());
        gen.writeEndObject();
    }
}

在User.java 加上

@JsonSerialize(using = UserCustomSerializer.class)

重新查詢,取得實作類自定的欄位名稱userid, username


總結:
上述為本身在實際開發應用上會遇到的問題,希望能藉此幫助到有需要的人,Jackson是目前Java在處理資料綁定和資料格式轉換的好用工具,未來還會在發表相關文章,與大家分享

 

 

 

蔡維宇