typescript-generator icon indicating copy to clipboard operation
typescript-generator copied to clipboard

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

Open andrewbents opened this issue 2 years ago • 2 comments

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?

andrewbents avatar Feb 11 '22 23:02 andrewbents

Likely related to #794 I was running into this issue as well and rolled the version back - it no longer (incorrectly) performs a string breakdown based on the names and goes back to ignoring the annotation and using the field's type, which is technically more correct

Yidna avatar Jul 06 '22 20:07 Yidna

make sure you have a .java script for estimating the errors

durgasatti avatar Sep 21 '22 04:09 durgasatti