Jackson 自訂 Serialize & Deserialize
2019/12/31 11:54:30
0
1661
首先建立一組 REST API 功能是對User的CRUD操作
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時所帶入的birthDate為String時,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在處理資料綁定和資料格式轉換的好用工具,未來還會在發表相關文章,與大家分享