Skip to content

PR #582 in combination with @JsonTypeInfo.defaultImpl generates an "incomplete" Tagged Union #613

@robertgartman

Description

@robertgartman

We ran into breaking changes when upgrading to v2.28.785, due to the new feature in #582. When using JsonTypeInfo in combination with a default class implementation (defaultImpl), then the resulting Tagged Union will capture all the @JsonSubTypes (as a result of #582) but miss the ones covered by the fallback defaultImpl. Not a bug, but perhaps a missing feature?

The short version

In v2.27.744, the provided example generates:

export interface INamedEntity {
    type?: INamedEntityType;
    entity?: string;
}

export enum INamedEntityType {
    O = "O",
    NORP = "NORP",
    ORGANIZATION = "ORGANIZATION",
    FACILITY = "FACILITY",
}

In v2.28.785, the provided example generates:

export interface INamedEntity {
    type: "DefaultEntity" | "FACILITY";
    entity?: string;
}

export enum INamedEntityType {
    O = "O",
    NORP = "NORP",
    ORGANIZATION = "ORGANIZATION",
    FACILITY = "FACILITY",
}

Issue: Valid values for INamedEntity.type are the enums in INamedEntityType, not "DefaultEntity" | "FACILITY"

The verbose version

The issue is a result of having a default fallback implementation (defaultImpl = DefaultEntity.class in the example) in combination with JsonTypeInfo.Id.NAME and JsonTypeInfo.As.EXISTING_PROPERTY. The example has an enum as the name property but I assume the issue will be present also with a String.

Is there a way of keeping the pre-2.28.785 behaviour, or perhaps have the type attribute include all the enum values? Creating an object in the TypeScript domain that implements INamedEntity will, for obvious reasons fail, when setting type='NORP'.

A complete example is provided here: https://github.com/avtalsbanken/typescript-generator

Code from the example repo included below:

package my.example.app;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXISTING_PROPERTY,
    property = "type",
    defaultImpl = DefaultEntity.class
)
@JsonSubTypes({
    @JsonSubTypes.Type(
        value = FacilityEntity.class,
        name = "FACILITY"
    )
})
abstract class NamedEntity {

    public final NamedEntityType type;

    private String entity;

    public NamedEntity(NamedEntityType type) {
        this.type = type;
    }

    public String getEntity() {
        return entity;
    }

    public void setEntity(String entity) {
        this.entity = entity;
    }
}
package my.example.app;

/**
 * A tiny subset of Named Entities
 */
public enum NamedEntityType {
    O /* Other */,
    NORP /* Nationalities or religious or political groups */,
    ORGANIZATION /* Companies, agencies, institutions, etc */,
    FACILITY /* Buildings, airports, highways, bridges, etc. */
}
package my.example.app;

public class DefaultEntity extends NamedEntity{

    public DefaultEntity(NamedEntityType type) {
        super(type);
    }
}
package my.example.app;

public class FacilityEntity extends NamedEntity {

    private String geoCoordinates;

    public FacilityEntity() {
        super(NamedEntityType.FACILITY);
    }

    public String getGeoCoordinates() {
        return geoCoordinates;
    }

    public void setGeoCoordinates(String geoCoordinates) {
        this.geoCoordinates = geoCoordinates;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions