Passing objects with class inheritance causes wrong deserialisation

Hi, TLDR we have implemented the following (the comments contain the reasoning). Maybe it was not necessary and there exists a more elegant solution.


/**
 * Because Temporal stores data serialised without having access to the class definitions, it stores type
 * information based on the declared type. This applies to all types of methods: Workflows, Signals, Queries,
 * Activities. In case the objects passed are descendants of that type, this information is lost. Then during
 * deserialisation critical errors of type UnknownProperty will cause failure.
 * To overcome that problem we need to manually store the exact type and then deserialise to that type. To trick
 * the serialisation layer data is first transformed to a Tree which is generic and will be deserialised exactly,
 * and then we convert back to the right object by using the type information stored in a separate top-level
 * attribute.
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class WrappedPayload implements Serializable {
    static ObjectMapper MAPPER = new ObjectMapper(); // must be static

    static {
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        MAPPER.registerModule(new JavaTimeModule());
    }

    String type;
    JsonNode data;

    public static WrappedPayload of(MessagePayload data) {
        return new WrappedPayload(
                data.getClass().getTypeName(),
                MAPPER.valueToTree(data));
    }

    public void replace(MessagePayload data) {
        if (!data.getClass().getTypeName().equals(type)) {
            throw new IllegalArgumentException("The type wrapped is immutable");
        }
        this.data = MAPPER.valueToTree(data);
    }

    public MessagePayload getData() {
        try {
            return (MessagePayload) MAPPER.treeToValue(data, Class.forName(type));
        } catch (ClassNotFoundException | JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public String dataAsString() {
        return data.toString();
    }

}