Skip to content

Commit 23a4384

Browse files
Paweł Płazieńskivojtechhabarta
authored andcommitted
Allow generating constructors for child classes (#337)
1 parent 5866033 commit 23a4384

File tree

4 files changed

+75
-18
lines changed

4 files changed

+75
-18
lines changed

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/compiler/ModelCompiler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public enum TransformationPhase {
4848
BeforeTsModel,
4949
BeforeEnums,
5050
BeforeSymbolResolution,
51+
AfterDeclarationSorting,
5152
}
5253

5354
public TsModel javaToTypeScript(Model model) {
@@ -108,6 +109,7 @@ public TsModel javaToTypeScript(Model model) {
108109
symbolTable.resolveSymbolNames();
109110
tsModel = removeDeclarationsImportedFromDependencies(symbolTable, tsModel);
110111
tsModel = sortDeclarations(symbolTable, tsModel);
112+
tsModel = applyExtensionTransformers(symbolTable, tsModel, TransformationPhase.AfterDeclarationSorting, extensionTransformers);
111113
return tsModel;
112114
}
113115

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/ext/RequiredPropertyConstructorExtension.java

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import cz.habarta.typescript.generator.emitter.EmitterExtensionFeatures;
1111
import cz.habarta.typescript.generator.emitter.TsAssignmentExpression;
1212
import cz.habarta.typescript.generator.emitter.TsBeanModel;
13+
import cz.habarta.typescript.generator.emitter.TsCallExpression;
1314
import cz.habarta.typescript.generator.emitter.TsConstructorModel;
1415
import cz.habarta.typescript.generator.emitter.TsEnumModel;
1516
import cz.habarta.typescript.generator.emitter.TsExpression;
@@ -22,10 +23,12 @@
2223
import cz.habarta.typescript.generator.emitter.TsPropertyModel;
2324
import cz.habarta.typescript.generator.emitter.TsStatement;
2425
import cz.habarta.typescript.generator.emitter.TsStringLiteral;
26+
import cz.habarta.typescript.generator.emitter.TsSuperExpression;
2527
import cz.habarta.typescript.generator.emitter.TsThisExpression;
2628

2729
import java.util.ArrayList;
2830
import java.util.Arrays;
31+
import java.util.HashMap;
2932
import java.util.List;
3033
import java.util.Map;
3134
import java.util.Optional;
@@ -55,38 +58,60 @@ public void setConfiguration(Map<String, String> configuration) throws RuntimeEx
5558

5659
@Override
5760
public List<TransformerDefinition> getTransformers() {
58-
return Arrays.asList(new TransformerDefinition(ModelCompiler.TransformationPhase.BeforeSymbolResolution, new ModelTransformer() {
61+
return Arrays.asList(new TransformerDefinition(ModelCompiler.TransformationPhase.AfterDeclarationSorting, new ModelTransformer() {
5962
@Override
6063
public TsModel transformModel(SymbolTable symbolTable, TsModel model) {
6164
List<TsBeanModel> beans = new ArrayList<>();
65+
Map<String, TsConstructorModel> generatedConstructors = new HashMap<>();
6266
for (TsBeanModel bean : model.getBeans()) {
63-
TsBeanModel newBean = transformBean(bean, model);
67+
TsBeanModel newBean = transformBean(bean, model, generatedConstructors);
6468
beans.add(newBean);
6569
}
6670
return model.withBeans(beans);
6771
}
6872
}));
6973
}
7074

71-
private TsBeanModel transformBean(TsBeanModel bean, TsModel model) {
75+
private TsBeanModel transformBean(TsBeanModel bean, TsModel model,
76+
Map<String, TsConstructorModel> generatedConstructors) {
7277
if (!bean.isClass() || bean.getConstructor() != null) {
7378
return bean;
7479
}
75-
Optional<TsConstructorModel> constructorOption = createConstructor(bean, model);
80+
Optional<TsConstructorModel> constructorOption = createConstructor(bean, model, generatedConstructors);
7681
if (!constructorOption.isPresent()) {
7782
return bean;
7883
}
7984
if (classes != null && !classes.contains(bean.getOrigin().getCanonicalName())) {
8085
return bean;
8186
}
82-
return bean.withConstructor(constructorOption.get());
87+
TsConstructorModel constructor = constructorOption.get();
88+
generatedConstructors.put(bean.getName().getFullName(), constructor);
89+
return bean.withConstructor(constructor);
8390
}
8491

85-
private static Optional<TsConstructorModel> createConstructor(TsBeanModel bean, TsModel model) {
92+
private static Optional<TsConstructorModel> createConstructor(TsBeanModel bean, TsModel model,
93+
Map<String, TsConstructorModel> generatedConstructors) {
8694
List<TsParameterModel> parameters = new ArrayList<>();
8795
List<TsStatement> body = new ArrayList<>();
88-
if (bean.getParent() != null) {
89-
throw new IllegalStateException("Creating constructors for inherited beans is not currently supported");
96+
TsType parent = bean.getParent();
97+
if (parent != null) {
98+
if (!(parent instanceof TsType.ReferenceType)) {
99+
throw new IllegalStateException("Generating constructor for non-reference parent types is not currently supported");
100+
}
101+
TsType.ReferenceType referenceParent = (TsType.ReferenceType) parent;
102+
TsConstructorModel parentConstructor = generatedConstructors.get(referenceParent.symbol.getFullName());
103+
if (parentConstructor == null) {
104+
throw new IllegalStateException("Generating constructor for class with non-generated constructor is not currently supported");
105+
}
106+
List<TsParameterModel> parentParameters = parentConstructor.getParameters();
107+
TsIdentifierReference[] callParameters = new TsIdentifierReference[parentParameters.size()];
108+
int i = 0;
109+
for (TsParameterModel parentParameter : parentParameters) {
110+
parameters.add(parentParameter);
111+
callParameters[i] = new TsIdentifierReference(parentParameter.name);
112+
i++;
113+
}
114+
body.add(new TsExpressionStatement(new TsCallExpression(new TsSuperExpression(), callParameters)));
90115
}
91116
for (TsPropertyModel property : bean.getProperties()) {
92117
if (!property.modifiers.isReadonly) {

typescript-generator-core/src/test/java/cz/habarta/typescript/generator/ext/RequiredPropertyConstructorExtensionTest.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,8 @@ static class PolymorphicClass implements SuperInterface {
5858
public int field1;
5959
}
6060

61-
@JsonTypeName("class-c")
62-
static class SecondClass extends PolymorphicClass {
63-
public int field2;
61+
static class SecondClass extends SimpleClass {
62+
public int field3;
6463
}
6564

6665
@Test
@@ -118,13 +117,10 @@ public void testInheritance() {
118117
Settings settings = createBaseSettings();
119118
settings.declarePropertiesAsReadOnly = true;
120119

121-
try {
122-
generateTypeScript(settings, SecondClass.class);
123-
Assert.fail("Expected exception");
124-
}
125-
catch (IllegalStateException expected) {
126-
Assert.assertEquals("Creating constructors for inherited beans is not currently supported", expected.getMessage());
127-
}
120+
String result = generateTypeScript(settings, SecondClass.class);
121+
122+
String expected = readResource("inheritance.ts");
123+
Assert.assertEquals(expected, result);
128124
}
129125

130126
private static String generateTypeScript(Settings settings, Type... types) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* tslint:disable */
2+
3+
export class PolymorphicClass implements SuperInterface {
4+
readonly discriminator: "class-b";
5+
readonly field1: number;
6+
7+
constructor(field1: number) {
8+
this.discriminator = "class-b";
9+
this.field1 = field1;
10+
}
11+
}
12+
13+
export class SimpleClass {
14+
readonly field1: string;
15+
readonly field2: PolymorphicClass;
16+
17+
constructor(field1: string, field2: PolymorphicClass) {
18+
this.field1 = field1;
19+
this.field2 = field2;
20+
}
21+
}
22+
23+
export class SecondClass extends SimpleClass {
24+
readonly field3: number;
25+
26+
constructor(field1: string, field2: PolymorphicClass, field3: number) {
27+
super(field1, field2);
28+
this.field3 = field3;
29+
}
30+
}
31+
32+
export interface SuperInterface {
33+
readonly discriminator: "class-b";
34+
}

0 commit comments

Comments
 (0)