TranslatedWorkflowStepDTOSerializer.java
/*
* Copyright 2026 Global Crop Diversity Trust
* Licensed under the Apache License, Version 2.0
* See LICENSE file in project root folder or http://www.apache.org/licenses/LICENSE-2.0
*/
package org.gringlobal.custom.json.serializer;
import java.io.IOException;
import java.util.Map;
import org.gringlobal.api.model.TranslatedWorkflowStepDTO;
import org.gringlobal.api.model.TranslatedWorkflowStepDTO.TranslatedWorkflowActionStepDTO;
import org.gringlobal.api.model.WorkflowStepDTO;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
/**
* Custom serializer for TranslatedWorkflowStepDTO that inlines (unwraps) the
* fields of the underlying {@link WorkflowStepDTO} and also injects the "_class"
* property with the simple class name of the DTO subtype. This avoids Jackson's
* {@link SerializationFeature#FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS} error when using {@link JsonUnwrapped} together
* with EXISTING_PROPERTY type info on the wrapped type.
*/
public class TranslatedWorkflowStepDTOSerializer extends JsonSerializer<TranslatedWorkflowStepDTO<?>> {
@Override
public void serializeWithType(TranslatedWorkflowStepDTO<?> value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
ObjectMapper mapper = (ObjectMapper) gen.getCodec();
gen.writeStartObject();
var entity = value != null ? value.getEntity() : null;
if (entity != null) {
for (Map.Entry<String, JsonNode> e : mapper.valueToTree(entity).properties()) {
gen.writeFieldName(e.getKey());
mapper.writeValue(gen, e.getValue());
}
}
// Write Translated fields
if (value != null) {
if (value.getTitle() != null) {
gen.writeStringField("title", value.getTitle());
}
if (value.getDescription() != null) {
gen.writeStringField("description", value.getDescription());
}
if (value instanceof TranslatedWorkflowActionStepDTO) {
var tas = (TranslatedWorkflowActionStepDTO) value;
gen.writeStringField("conditionMessage", tas.getConditionMessage());
gen.writeStringField("actionNote", tas.getActionNote());
}
}
gen.writeEndObject();
}
@Override
public void serialize(TranslatedWorkflowStepDTO<?> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
ObjectMapper mapper = (ObjectMapper) gen.getCodec();
gen.writeStartObject();
var entity = value != null ? value.getEntity() : null;
if (entity != null) {
for (Map.Entry<String, JsonNode> e : mapper.valueToTree(entity).properties()) {
gen.writeFieldName(e.getKey());
mapper.writeValue(gen, e.getValue());
}
}
// Write Translated fields
if (value != null) {
if (value.getTitle() != null) {
gen.writeStringField("title", value.getTitle());
}
if (value.getDescription() != null) {
gen.writeStringField("description", value.getDescription());
}
if (value instanceof TranslatedWorkflowActionStepDTO) {
var tas = (TranslatedWorkflowActionStepDTO) value;
gen.writeStringField("conditionMessage", tas.getConditionMessage());
gen.writeStringField("actionNote", tas.getActionNote());
}
}
gen.writeEndObject();
}
}