I need to write a custom Serializer for one of my entities "Payment" and I have to implement it by extending StdSerializer
:
class Payment {
}
class PaymentSerializer extends StdSerializer<Payment> {
public PaymentSerializer() {
this(null);
}
public PaymentSerializer(Class<Payment> t) {
super(t);
}
@Override
public void serialize(Payment value, JsonGenerator gen, SerializerProvider provider) throws IOException {
// some logics
}
}
Since I use Spring, I register this Serializer so Spring could identify it:
@Bean
public Jackson2ObjectMapperBuilder serializersObjectMapperBuilder() {
SimpleModule module = new SimpleModule();
module.addSerializer(Payment.class, applicationContext.getBean(PaymentSerializer.class));
return new Jackson2ObjectMapperBuilder().modules(module);
}
Now I have a controller that returns data back to the client and it uses this Serializer without any problem:
@RestController
@RequestMapping("/payment")
class PaymentController {
@GetMapping
public List<Payment> getAll() {
return Arrays.asList(new Payment());
}
}
Since now, my Serializer works fine and everything is good.
The problem is with another entity "Order" which has Payment as a property with @JsonUnwrapped
:
class Order {
@JsonUnwrapped
private Payment payment;
}
I need to unwrap the Payment
inside the Order
and I want to use the same PaymentSerializer but the problem is when I use this custom Serializer, the @JsonUnwrapped
annotation will be ignored and the output will be something like this:
{
"payment": {
.....
}
}
As I mentioned, I want to eliminate the "payment" field and unwrap it.
I know that for emulating @JsonUnwrapped
for a custom Serializer I need to extend UnwrappingBeanSerializer
class, but as I mentioned at first, I need the standard Serializer too.
Changing my entity models is not an option for me.
Is there any way to accomplish this?
I use Spring Boot 2.1.3.RELEASE
which I believe uses Jackson 2.9
I propose the following way to solve issue:
We can compose two StdSerializer
in single custom serializer.
@Component
class PaymentSerializer extends StdSerializer<Payment> {
private final JsonSerializer<Payment> delegate = new UnwrappingPaymentSerializer(NameTransformer.NOP);
public PaymentSerializer() {
this(null);
}
public PaymentSerializer(Class<Payment> t) {
super(t);
}
@Override
public void serialize(Payment value, JsonGenerator generator, SerializerProvider provider) throws IOException {
generator.writeStartObject();
this.delegate.serialize(value, generator, provider);
generator.writeEndObject();
}
@Override
public JsonSerializer<Payment> unwrappingSerializer(final NameTransformer nameTransformer) {
return new UnwrappingPaymentSerializer(nameTransformer);
}
}
And unwrapping:
public class UnwrappingPaymentSerializer extends JsonSerializer<Payment> {
private NameTransformer transformer;
public UnwrappingPaymentSerializer(NameTransformer transformer) {
this.transformer = transformer;
}
@Override
public void serialize(Payment value, JsonGenerator generator, SerializerProvider provider) throws IOException {
// some logics
}
@Override
public boolean isUnwrappingSerializer() {
return true;
}
}
As result you have single serializer for serialization and unwrapping. For more details see: https://michael-simons.github.io/simple-meetup/unwrapping-custom-jackson-serializer
Let me know if solution is not applicable, and I will try to propose other way depends on project requirements.