Jackson API ให้ความยืดหยุ่นในการ serialize object โดยการ implement Custom Serializer ผ่านการ extends คลาส StdSerializer<T> และ override เมธอด serialize(T value, JsonGenerator gen, SerializerProvider provider)
Signature ของเมธอด serialize
public abstract void serialize(T value, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException
พารามิเตอร์:
- value - object ที่จะ serialize (ไม่เป็น null)
- gen - JsonGenerator สำหรับเขียน JSON output
- provider - SerializerProvider สำหรับดึง serializer อื่นๆ มาใช้
ตัวอย่างโค้ดครบถ้วน
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
public class JacksonCustomSerializerTest {
public static void main(String[] args) throws Exception {
User user = new User();
user.setFirstName("Raja");
user.setLastName("Ramesh");
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(User.class, new UserSerializer());
mapper.registerModule(module);
String jsonStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
System.out.println(jsonStr);
}
}
// User class (POJO)
class User implements Serializable {
private String firstName;
private String lastName;
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
}
// Custom Serializer
class UserSerializer extends StdSerializer<User> {
public UserSerializer() { this(null); }
public UserSerializer(Class<User> t) { super(t); }
@Override
public void serialize(User value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {
jgen.writeStartObject();
jgen.writeStringField("firstName", value.getFirstName());
jgen.writeStringField("lastName", value.getLastName());
// สามารถเพิ่ม computed field ได้
jgen.writeStringField("fullName", value.getFirstName() + " " + value.getLastName());
jgen.writeEndObject();
}
}
ผลลัพธ์
{
"firstName" : "Raja",
"lastName" : "Ramesh",
"fullName" : "Raja Ramesh"
}
การใช้งานขั้นสูง
1. ใช้ JsonSerializer แทน StdSerializer (Generic)
class UserSerializer extends JsonSerializer<User> {
@Override
public void serialize(User value, JsonGenerator gen, SerializerProvider provider)
throws IOException { ... }
}
2. ใช้ ContextualSerializer สำหรับการ configure แบบ dynamic
class UserSerializer extends StdSerializer<User> implements ContextualSerializer {
private boolean includeFullName;
public UserSerializer() { this(null); }
public UserSerializer(Class<User> t) { super(t); }
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty prop) {
JsonInclude inc = prop.getAnnotation(JsonInclude.class);
boolean include = inc != null; // logic ตัดสินใจ
return new UserSerializer(include);
}
// ...
}
3. ใช้ @JsonSerialize บน field/class โดยตรง
class Employee {
@JsonSerialize(using = UserSerializer.class)
private User user;
// ...
}
เมื่อไหร่ควรใช้ Custom Serializer
- ต้องการเปลี่ยนชื่อฟิลด์ / โครงสร้าง JSON ให้ต่างจาก POJO
- ต้องคำนวณค่าเพิ่มเติม (computed fields)
- ต้อง serialize object ที่ไม่ได้ควบคุม source code (third-party class)
- ต้องจัดการ circular reference เอง
- ต้องการ format เฉพาะ (เช่น date format custom)
ข้อควรระวัง
- ต้องจดทะเบียนผ่าน
SimpleModuleและmapper.registerModule() - Custom serializer จะ override annotation ทั้งหมดบน class นั้น
- ประสิทธิภาพ: JsonGenerator เขียน streaming ตรงๆ เร็วกว่าสร้าง tree model