Skip to content

@JsonSubTypes.Type names are neglected, only the first name is emitted #796

Open
@andrewbents

Description

@andrewbents

Jackson supports specifying names for subtypes, so the following is possible

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.EXISTING_PROPERTY,
        property = "type",
        visible = true
)
@JsonSubTypes({
        @JsonSubTypes.Type(value = LongDto.class, names = {"Price", "Duration"}),
        @JsonSubTypes.Type(value = BoolDto.class, names = {"Official", "Signer"}),
})
static class AbstractDto {
    public String type;
}

static class LongDto extends AbstractDto {
    public long value;

    @Override
    public String toString() {
        return "LongDto{" +
                "type='" + type + '\'' +
                ", value=" + value +
                '}';
    }
}

static class BoolDto extends AbstractDto {
    public boolean value;

    @Override public String toString() {
        return "BoolDto{" +
                "type='" + type + '\'' +
                ", value=" + value +
                '}';
    }
}

@Test
void test() throws JsonProcessingException {
    LongDto priceDto = new LongDto();
    priceDto.type = "Price";
    priceDto.value = 100;
    LongDto durationDto = new LongDto();
    durationDto.type = "Duration";
    durationDto.value = 2;

    BoolDto boolDto = new BoolDto();
    boolDto.type = "Official";
    boolDto.value = true;

    ObjectMapper objectMapper = new ObjectMapper();
    String jsonString = objectMapper.writeValueAsString(List.of(priceDto, boolDto, durationDto));
    System.out.println(jsonString); // [{"type":"Price","value":100},{"type":"Official","value":true},{"type":"Duration","value":2}]
    System.out.println(objectMapper.readValue(jsonString, new TypeReference<List<AbstractDto>>() { }));  // [LongDto{type='Price', value=100}, BoolDto{type='Official', value=true}, LongDto{type='Duration', value=2}]
}

I would expect the generator to emit something like this:

export interface AbstractDto {
  'type': 'Price' | 'Duration' | 'Official' | 'Signer';
}

export interface BoolDto extends AbstractDto {
  type: 'Official' | 'Signer';
  value: boolean;
}

export interface LongDto extends AbstractDto {
  type: 'Price' | 'Duration'';
  value: number;
}

export type AbstractDtoUnion = BoolDto | LongDto;

But the actual output is like this (only first name is taken of each type):

export interface AbstractDto {
  type: 'Official' | 'Price';
}

export interface BoolDto extends AbstractDto {
  type: 'Official';
  value: boolean;
}

export interface LongDto extends AbstractDto {
  type: 'Price';
  value: number;
}

export type AbstractDtoUnion = LongDto | BoolDto;

is it possible to support this case?

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