diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java index 5c91e7482..f1068e9dc 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java @@ -306,8 +306,10 @@ private TsBeanModel processBean(SymbolTable symbolTable, Model model, Map descendants = selfAndDescendants.subList(1, selfAndDescendants.size()); @@ -339,7 +341,7 @@ private TsBeanModel processBean(SymbolTable symbolTable, Model model, Map implementsList; private final List> taggedUnionClasses; private final String discriminantProperty; - private final String discriminantLiteral; + private final List discriminantLiterals; private final TsAliasModel taggedUnionAlias; private final List properties; private final TsConstructorModel constructor; @@ -52,7 +52,7 @@ private TsBeanModel( List implementsList, List> taggedUnionClasses, String discriminantProperty, - String discriminantLiteral, + List discriminantLiterals, TsAliasModel taggedUnionAlias, List properties, TsConstructorModel constructor, @@ -67,7 +67,7 @@ private TsBeanModel( this.implementsList = Utils.listFromNullable(implementsList); this.taggedUnionClasses = Utils.listFromNullable(taggedUnionClasses); this.discriminantProperty = discriminantProperty; - this.discriminantLiteral = discriminantLiteral; + this.discriminantLiterals = discriminantLiterals; this.taggedUnionAlias = taggedUnionAlias; this.properties = Utils.listFromNullable(properties); this.constructor = constructor; @@ -83,7 +83,7 @@ public List getDecorators() { } public TsBeanModel withDecorators(List decorators) { - return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiteral, taggedUnionAlias, properties, constructor, methods, comments); + return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiterals, taggedUnionAlias, properties, constructor, methods, comments); } public List getTypeParameters() { @@ -117,12 +117,12 @@ public String getDiscriminantProperty() { return discriminantProperty; } - public String getDiscriminantLiteral() { - return discriminantLiteral; + public List getDiscriminantLiterals() { + return discriminantLiterals; } - public TsBeanModel withTaggedUnion(List> taggedUnionClasses, String discriminantProperty, String discriminantLiteral) { - return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiteral, taggedUnionAlias, properties, constructor, methods, comments); + public TsBeanModel withTaggedUnion(List> taggedUnionClasses, String discriminantProperty, List discriminantLiterals) { + return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiterals, taggedUnionAlias, properties, constructor, methods, comments); } public TsAliasModel getTaggedUnionAlias() { @@ -130,7 +130,7 @@ public TsAliasModel getTaggedUnionAlias() { } public TsBeanModel withTaggedUnionAlias(TsAliasModel taggedUnionAlias) { - return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiteral, taggedUnionAlias, properties, constructor, methods, comments); + return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiterals, taggedUnionAlias, properties, constructor, methods, comments); } public List getProperties() { @@ -138,7 +138,7 @@ public List getProperties() { } public TsBeanModel withProperties(List properties) { - return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiteral, taggedUnionAlias, properties, constructor, methods, comments); + return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiterals, taggedUnionAlias, properties, constructor, methods, comments); } public TsConstructorModel getConstructor() { @@ -146,7 +146,7 @@ public TsConstructorModel getConstructor() { } public TsBeanModel withConstructor(TsConstructorModel constructor) { - return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiteral, taggedUnionAlias, properties, constructor, methods, comments); + return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiterals, taggedUnionAlias, properties, constructor, methods, comments); } public List getMethods() { @@ -154,7 +154,7 @@ public List getMethods() { } public TsBeanModel withMethods(List methods) { - return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiteral, taggedUnionAlias, properties, constructor, methods, comments); + return new TsBeanModel(origin, category, isClass, decorators, name, typeParameters, parent, extendsList, implementsList, taggedUnionClasses, discriminantProperty, discriminantLiterals, taggedUnionAlias, properties, constructor, methods, comments); } public boolean isJaxrsApplicationClientBean() { diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsSwitchCaseClause.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsSwitchCaseClause.java index e893875a6..efd0fb440 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsSwitchCaseClause.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/emitter/TsSwitchCaseClause.java @@ -6,16 +6,16 @@ public class TsSwitchCaseClause extends TsStatement { - private final TsExpression expression; + private final List expressions; private final List statements; - public TsSwitchCaseClause(TsExpression expression, List statements) { - this.expression = expression; + public TsSwitchCaseClause(List expressions, List statements) { + this.expressions = expressions; this.statements = statements; } - public TsExpression getExpression() { - return expression; + public List getExpressions() { + return expressions; } public List getStatements() { diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/JsonDeserializationExtension.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/JsonDeserializationExtension.java index 11785798b..5d7d99f64 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/JsonDeserializationExtension.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/JsonDeserializationExtension.java @@ -47,6 +47,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; public class JsonDeserializationExtension extends Extension { @@ -321,7 +322,7 @@ private static TsMethodModel createDeserializationMethodForTaggedUnion(SymbolTab for (Class cls : bean.getTaggedUnionClasses()) { final TsBeanModel tuBean = tsModel.getBean(cls); caseClauses.add(new TsSwitchCaseClause( - new TsStringLiteral(tuBean.getDiscriminantLiteral()), + tuBean.getDiscriminantLiterals().stream().map(TsStringLiteral::new).collect(Collectors.toList()), Arrays.asList(new TsReturnStatement( new TsCallExpression( new TsMemberExpression(new TsTypeReferenceExpression(new TsType.ReferenceType(symbolTable.getSymbol(cls))), "fromData"), diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/BeanModel.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/BeanModel.java index 3e7922f36..4129d048d 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/BeanModel.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/BeanModel.java @@ -13,16 +13,16 @@ public class BeanModel extends DeclarationModel { private final Type parent; private final List> taggedUnionClasses; private final String discriminantProperty; - private final String discriminantLiteral; + private final List discriminantLiterals; private final List interfaces; private final List properties; - public BeanModel(Class origin, Type parent, List> taggedUnionClasses, String discriminantProperty, String discriminantLiteral, List interfaces, List properties, List comments) { + public BeanModel(Class origin, Type parent, List> taggedUnionClasses, String discriminantProperty, List discriminantLiterals, List interfaces, List properties, List comments) { super(origin, comments); this.parent = parent; this.taggedUnionClasses = taggedUnionClasses; this.discriminantProperty = discriminantProperty; - this.discriminantLiteral = discriminantLiteral; + this.discriminantLiterals = discriminantLiterals; this.interfaces = Utils.listFromNullable(interfaces); this.properties = properties; } @@ -39,8 +39,8 @@ public String getDiscriminantProperty() { return discriminantProperty; } - public String getDiscriminantLiteral() { - return discriminantLiteral; + public List getDiscriminantLiterals() { + return discriminantLiterals; } public List getInterfaces() { @@ -68,12 +68,12 @@ public PropertyModel getProperty(String name) { } public BeanModel withProperties(List properties) { - return new BeanModel(origin, parent, taggedUnionClasses, discriminantProperty, discriminantLiteral, interfaces, properties, comments); + return new BeanModel(origin, parent, taggedUnionClasses, discriminantProperty, discriminantLiterals, interfaces, properties, comments); } @Override public BeanModel withComments(List comments) { - return new BeanModel(origin, parent, taggedUnionClasses, discriminantProperty, discriminantLiteral, interfaces, properties, comments); + return new BeanModel(origin, parent, taggedUnionClasses, discriminantProperty, discriminantLiterals, interfaces, properties, comments); } @Override diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java index 82edd895d..7ad4a1eab 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/parser/Jackson2Parser.java @@ -296,7 +296,7 @@ private BeanModel parseBean(SourceType> sourceClass, List class final String discriminantProperty; final boolean syntheticDiscriminantProperty; - final String discriminantLiteral; + final List discriminantLiterals; final Pair, JsonTypeInfo> classWithJsonTypeInfo = Pair.of(sourceClass.type, sourceClass.type.getAnnotation(JsonTypeInfo.class)); final Pair, JsonTypeInfo> parentClassWithJsonTypeInfo; @@ -305,18 +305,18 @@ private BeanModel parseBean(SourceType> sourceClass, List class final JsonTypeInfo jsonTypeInfo = classWithJsonTypeInfo.getValue2(); discriminantProperty = getDiscriminantPropertyName(jsonTypeInfo); syntheticDiscriminantProperty = isDiscriminantPropertySynthetic(jsonTypeInfo); - discriminantLiteral = isInterfaceOrAbstract(sourceClass.type) ? null : getTypeName(sourceClass.type); + discriminantLiterals = isInterfaceOrAbstract(sourceClass.type) ? null : getTypeNames(sourceClass.type); } else if (isTaggedUnion(parentClassWithJsonTypeInfo = getAnnotationRecursive(sourceClass.type, JsonTypeInfo.class))) { // this is child class final JsonTypeInfo parentJsonTypeInfo = parentClassWithJsonTypeInfo.getValue2(); discriminantProperty = getDiscriminantPropertyName(parentJsonTypeInfo); syntheticDiscriminantProperty = isDiscriminantPropertySynthetic(parentJsonTypeInfo); - discriminantLiteral = getTypeName(sourceClass.type); + discriminantLiterals = getTypeNames(sourceClass.type); } else { // not part of explicit hierarchy discriminantProperty = null; syntheticDiscriminantProperty = false; - discriminantLiteral = null; + discriminantLiterals = null; } if (discriminantProperty != null) { @@ -355,7 +355,7 @@ private BeanModel parseBean(SourceType> sourceClass, List class for (Type aInterface : interfaces) { addBeanToQueue(new SourceType<>(aInterface, sourceClass.type, "")); } - return new BeanModel(sourceClass.type, superclass, taggedUnionClasses, discriminantProperty, discriminantLiteral, interfaces, properties, classComments); + return new BeanModel(sourceClass.type, superclass, taggedUnionClasses, discriminantProperty, discriminantLiterals, interfaces, properties, classComments); } private static Integer getCreatorIndex(BeanProperty beanProperty) { @@ -443,12 +443,7 @@ private String getDiscriminantPropertyName(JsonTypeInfo jsonTypeInfo) { : jsonTypeInfo.property(); } - private String getTypeName(Class cls) { - final List typeNames = getTypeNamesOrEmptyOrNull(cls); - return typeNames != null && !typeNames.isEmpty() ? typeNames.get(0) : null; - } - - private List getTypeNamesOrEmptyOrNull(Class cls) { + private List getTypeNames(Class cls) { try { final SerializationConfig config = objectMapper.getSerializationConfig(); final JavaType javaType = config.constructType(cls); diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/Jackson2ParserTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/Jackson2ParserTest.java index 06262e076..8616ab6b9 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/Jackson2ParserTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/Jackson2ParserTest.java @@ -97,10 +97,10 @@ public void testTaggedUnion() { Assertions.assertNull(bean2.getTaggedUnionClasses()); Assertions.assertNull(bean3.getTaggedUnionClasses()); Assertions.assertEquals("kind", bean0.getDiscriminantProperty()); - Assertions.assertEquals("explicit-name1", bean1.getDiscriminantLiteral()); - Assertions.assertEquals("SubType2", bean2.getDiscriminantLiteral()); - Assertions.assertEquals("Jackson2ParserTest$SubTypeDiscriminatedByName3", bean3.getDiscriminantLiteral()); - Assertions.assertEquals("Jackson2ParserTest$SubTypeDiscriminatedByName4", bean4.getDiscriminantLiteral()); + Assertions.assertEquals(Arrays.asList("explicit-name1", "SubType1"), bean1.getDiscriminantLiterals()); + Assertions.assertEquals(Arrays.asList("SubType2"), bean2.getDiscriminantLiterals()); + Assertions.assertEquals(Arrays.asList("Jackson2ParserTest$SubTypeDiscriminatedByName3"), bean3.getDiscriminantLiterals()); + Assertions.assertEquals(Arrays.asList("Jackson2ParserTest$SubTypeDiscriminatedByName4"), bean4.getDiscriminantLiterals()); } @Test @@ -108,7 +108,7 @@ public void testRegisteredSubtypeName() { final Jackson2Parser jacksonParser = getJackson2Parser(); final Model model = jacksonParser.parseModel(SubTypeDiscriminatedByName5.class); final BeanModel bean5 = model.getBean(SubTypeDiscriminatedByName5.class); - Assertions.assertEquals("NamedByModule", bean5.getDiscriminantLiteral()); + Assertions.assertEquals(Arrays.asList("NamedByModule"), bean5.getDiscriminantLiterals()); } static Jackson2Parser getJackson2Parser() { @@ -132,7 +132,7 @@ public class InheritedClass { @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "kind") @JsonSubTypes({ - @JsonSubTypes.Type(value = SubTypeDiscriminatedByName1.class, name = "SubType1"), // value from @JsonTypeName is used + @JsonSubTypes.Type(value = SubTypeDiscriminatedByName1.class, name = "SubType1"), @JsonSubTypes.Type(value = SubTypeDiscriminatedByName2.class, name = "SubType2"), @JsonSubTypes.Type(value = SubTypeDiscriminatedByName3.class), @JsonSubTypes.Type(value = SubTypeDiscriminatedByName4.class), diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JsonDeserializationTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JsonDeserializationTest.java index 37167121a..c8f1b4adf 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JsonDeserializationTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/JsonDeserializationTest.java @@ -165,7 +165,7 @@ public static class Order { @JsonSubTypes({ @JsonSubTypes.Type(Square.class), @JsonSubTypes.Type(Rectangle.class), - @JsonSubTypes.Type(Circle.class), + @JsonSubTypes.Type(value = Circle.class, name = "circle2"), }) private abstract static class Shape { public ShapeMetadata metadata; diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/TaggedUnionsTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/TaggedUnionsTest.java index aa7cd78b6..bdfbd522c 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/TaggedUnionsTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/TaggedUnionsTest.java @@ -689,4 +689,44 @@ public void testIntermediateUnions() { Assertions.assertEquals(expected.trim(), output.trim()); } + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type") + @JsonSubTypes({ + @JsonSubTypes.Type(value = LongDto.class, names = {"Long1", "Long2"}), + @JsonSubTypes.Type(value = BoolDto.class, names = {"Bool1", "Bool2"}), + }) + private static abstract class AbstractDto { + public String type; + } + + private static class LongDto extends AbstractDto { + public long value; + } + + private static class BoolDto extends AbstractDto { + public boolean value; + } + + @Test + public void testMultipleDiscriminantLiterals() { + final Settings settings = TestUtils.settings(); + final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(AbstractDto.class)); + final String expected = "" + + "interface AbstractDto {\n" + + " type: \"Long1\" | \"Long2\" | \"Bool1\" | \"Bool2\";\n" + + "}\n" + + "\n" + + "interface LongDto extends AbstractDto {\n" + + " type: \"Long1\" | \"Long2\";\n" + + " value: number;\n" + + "}\n" + + "\n" + + "interface BoolDto extends AbstractDto {\n" + + " type: \"Bool1\" | \"Bool2\";\n" + + " value: boolean;\n" + + "}\n" + + "\n" + + "type AbstractDtoUnion = LongDto | BoolDto;\n" + + ""; + Assertions.assertEquals(expected.trim(), output.trim()); + } } diff --git a/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTest-expected.ts b/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTest-expected.ts index f0d074509..e44e6bdc9 100644 --- a/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTest-expected.ts +++ b/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTest-expected.ts @@ -92,7 +92,7 @@ export class Order { } export class Shape { - kind: "square" | "rectangle" | "circle"; + kind: "square" | "rectangle" | "circle" | "circle2"; metadata: ShapeMetadata; static fromData(data: Shape, target?: Shape): Shape { @@ -115,6 +115,7 @@ export class Shape { case "rectangle": return Rectangle.fromData(data); case "circle": + case "circle2": return Circle.fromData(data); } } @@ -166,7 +167,7 @@ export class Rectangle extends Shape { } export class Circle extends Shape { - kind: "circle"; + kind: "circle" | "circle2"; radius: number; static fromData(data: Circle, target?: Circle): Circle { diff --git a/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTestWithConstructors-expected.ts b/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTestWithConstructors-expected.ts index f4f4a29e9..179a7f9d2 100644 --- a/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTestWithConstructors-expected.ts +++ b/typescript-generator-core/src/test/resources/cz/habarta/typescript/generator/JsonDeserializationTestWithConstructors-expected.ts @@ -126,7 +126,7 @@ export class Order { } export class Shape { - kind: "square" | "rectangle" | "circle"; + kind: "square" | "rectangle" | "circle" | "circle2"; metadata: ShapeMetadata; constructor(data: Shape) { @@ -154,6 +154,7 @@ export class Shape { case "rectangle": return Rectangle.fromData(data); case "circle": + case "circle2": return Circle.fromData(data); } } @@ -220,7 +221,7 @@ export class Rectangle extends Shape { } export class Circle extends Shape { - kind: "circle"; + kind: "circle" | "circle2"; radius: number; constructor(data: Circle) { @@ -271,4 +272,4 @@ function __copyObject(object: { [index: string]: T }, itemCopyFn: (item: T) = function __identity(): (value: T) => T { return value => value; -} \ No newline at end of file +}