FasterXML / jackson-dataformats-text

Uber-project for (some) standard Jackson textual format backends: csv, properties, yaml (xml to be added in future)
Apache License 2.0
404 stars 148 forks source link

Yaml Output differs from Json Output for Subtypes #449

Closed micsport13 closed 9 months ago

micsport13 commented 9 months ago

I'm pretty new to Jackson so forgive me if this is a simple question or configuration that I'm just missing, but I'm trying to serialize a set of classes that implement an interface. When I use the default YAMLMapper , I get an output for one of the keys as !<TypeName> {}, yet when I use the JsonMapper, the output comes out as expected where it outputs something like

type:  { 
name: integer,
property1: value,
etc...
}

Yaml outputs as

type: !<integer> {}
  property1: value
  etc...

This is the main class:

@Getter
@JsonPropertyOrder({"name", "type", "constraints"})
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Column<T extends DataType<?>> {
  @JsonProperty("name")
  private final @NotNull String name;

  @JsonProperty("type")
  @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "name")
  private final @NotNull T dataType;

DataType class

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "name")
@JsonSubTypes({
  @JsonSubTypes.Type(value = IntegerDataType.class, name = "integer"),
  @JsonSubTypes.Type(value = VarcharDataType.class, name = "varchar"),
  @JsonSubTypes.Type(value = DecimalDataType.class, name = "decimal")
})
public interface DataType<T> {

One subtype class

@Getter
public class DecimalDataType implements DataType<BigDecimal> {
  @JsonProperty("precision")
  private final Integer precision;

  @JsonProperty("scale")
  final Integer scale;

Object Mapper usage

  private static final ObjectMapper objectMapper =
      //            new JsonMapper().enable(SerializationFeature.INDENT_OUTPUT);

      new YAMLMapper()
          .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
          .enable(YAMLGenerator.Feature.INDENT_ARRAYS)
          .enable(YAMLGenerator.Feature.INDENT_ARRAYS_WITH_INDICATOR)
          .enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)
          .enable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
          .enable(JsonGenerator.Feature.STRICT_DUPLICATE_DETECTION);

When I use new JsonMapper() instead of YamlMapper, I get the desired output. Is there something I'm doing wrong here?

cowtowncoder commented 9 months ago

I think there is a YAMLGenerator.Feature that controls whether "native" Type Id is used. I forget its name (let me know if you can't find it), and I think it is enabled by default. If so, it uses YAML's type id ("tag") to include id to be more YAML-like. If you disable that Feature, it'll instead use generic, JSON like Type Id.

micsport13 commented 9 months ago

Ah perfect. The relevant setting was to disable USE_NATIVE_TYPE_ID. What is the purpose of these type ids?

cowtowncoder commented 9 months ago

@micsport13 It is just "natural" thing to use for YAML: JSON does not have any special marker for type ids so it must use a regular property (or one of altenratives, wrapper Array or wrapper Object). But since YAML has, and many YAML tools expect tags, Jackson can also produce those (as well as read).

Or, if you prefer, cross-format alternatives that JSON uses.

So it's all for YAML compatibility.

There's equivalent thing for Object Ids ("anchors" in YAML) wrt @JsonIdentityInfo ids.

I hope this helps!

micsport13 commented 9 months ago

Thanks for the help! I'll have to look into this more because maybe that's better long term for my project.