Skip to content

Commit 019f6d4

Browse files
committed
added support for InterfaceRecordPropertiesAnnotationIntrospector
which automatically discovers record components on sealed interfaces
1 parent 1fdcdb4 commit 019f6d4

File tree

5 files changed

+113
-3
lines changed

5 files changed

+113
-3
lines changed

infobip-typescript-generator-extension-api/src/main/java/com/infobip/typescript/OrderedTypescriptGenerator.java

+16
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
package com.infobip.typescript;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.infobip.typescript.record.property.discovery.InterfaceRecordPropertyDiscoveryModule;
35
import cz.habarta.typescript.generator.Input;
46
import cz.habarta.typescript.generator.TypeScriptGenerator;
7+
import cz.habarta.typescript.generator.parser.Jackson2Parser;
58

69
public class OrderedTypescriptGenerator {
710
final TypeScriptGenerator generator;
811

912
public OrderedTypescriptGenerator(TypeScriptGenerator generator) {
1013
this.generator = generator;
14+
var typeScriptGeneratorObjectMapper = getObjectMapper(generator);
15+
typeScriptGeneratorObjectMapper.registerModule(new InterfaceRecordPropertyDiscoveryModule());
16+
}
17+
18+
private ObjectMapper getObjectMapper(TypeScriptGenerator generator) {
19+
var modelParser = (Jackson2Parser) generator.getModelParser();
20+
try {
21+
var field = Jackson2Parser.class.getDeclaredField("objectMapper");
22+
field.setAccessible(true);
23+
return (ObjectMapper) field.get(modelParser);
24+
} catch (Exception e) {
25+
throw new RuntimeException(e);
26+
}
1127
}
1228

1329
public String generateTypeScript(Input input) {

infobip-typescript-generator-extension-api/src/main/java/com/infobip/typescript/TypeScriptFileGenerator.java

-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import cz.habarta.typescript.generator.emitter.EmitterExtension;
1111
import cz.habarta.typescript.generator.emitter.TsModel;
1212
import cz.habarta.typescript.generator.parser.Model;
13-
import cz.habarta.typescript.generator.util.Utils;
1413

1514
import java.io.*;
1615
import java.lang.annotation.Annotation;
@@ -37,8 +36,6 @@ protected TypeScriptFileGenerator(Path basePath) {
3736
}
3837

3938
public void generate() {
40-
var objectMapper = Utils.getObjectMapper();
41-
objectMapper.findAndRegisterModules();
4239
List<EmitterExtension> extensions = createExtensions();
4340
Settings settings = createSettings(extensions);
4441
OrderedTypescriptGenerator generator = createGenerator(settings);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.infobip.typescript.record.property.discovery;
2+
3+
import com.fasterxml.jackson.databind.PropertyName;
4+
import com.fasterxml.jackson.databind.introspect.*;
5+
6+
import java.util.stream.Stream;
7+
8+
public class InterfaceRecordPropertiesAnnotationIntrospector extends NopAnnotationIntrospector {
9+
10+
@Override
11+
public PropertyName findNameForSerialization(Annotated a) {
12+
if(!(a instanceof AnnotatedMember annotatedMember)) {
13+
return super.findNameForSerialization(a);
14+
}
15+
16+
Class<?> declaringClass = annotatedMember.getDeclaringClass();
17+
18+
if(!declaringClass.isInterface()) {
19+
return super.findNameForSerialization(a);
20+
}
21+
22+
if(!declaringClass.isSealed()) {
23+
return super.findNameForSerialization(a);
24+
}
25+
26+
var hasRecordGetter = Stream.of(declaringClass.getPermittedSubclasses())
27+
.filter(Class::isRecord)
28+
.flatMap(subclass -> Stream.of(subclass.getRecordComponents()))
29+
.anyMatch(component -> component.getName().equals(a.getName()));
30+
31+
if(!hasRecordGetter) {
32+
return super.findNameForSerialization(a);
33+
}
34+
35+
return new PropertyName(a.getName());
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.infobip.typescript.record.property.discovery;
2+
3+
import com.fasterxml.jackson.databind.module.SimpleModule;
4+
5+
public class InterfaceRecordPropertyDiscoveryModule extends SimpleModule {
6+
7+
@Override
8+
public void setupModule(SetupContext context) {
9+
super.setupModule(context);
10+
context.insertAnnotationIntrospector(new InterfaceRecordPropertiesAnnotationIntrospector());
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.infobip.typescript.record.property.discovery;
2+
3+
import com.infobip.typescript.TestBase;
4+
import com.infobip.typescript.type.JsonTypeExtension;
5+
import cz.habarta.typescript.generator.Input;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.util.Collections;
9+
import java.util.stream.Stream;
10+
11+
import static org.assertj.core.api.BDDAssertions.then;
12+
13+
class InterfaceRecordPropertyDiscoveryTest extends TestBase {
14+
15+
InterfaceRecordPropertyDiscoveryTest() {
16+
super(new JsonTypeExtension(Stream::empty),
17+
Collections.emptyList());
18+
}
19+
20+
@Test
21+
void shouldAddReadonlyTypeField() {
22+
23+
// when
24+
String actual = whenGenerate(Input.from(HierarchyRoot.class,
25+
FirstLeaf.class));
26+
27+
// then
28+
then(actual).isEqualTo(
29+
"""
30+
31+
export interface HierarchyRoot {
32+
value: string;
33+
}
34+
35+
export class FirstLeaf implements HierarchyRoot {
36+
value: string;
37+
}
38+
""");
39+
}
40+
41+
sealed interface HierarchyRoot permits FirstLeaf {
42+
// @JsonGetter
43+
String value();
44+
}
45+
46+
record FirstLeaf(String value) implements HierarchyRoot {
47+
}
48+
}

0 commit comments

Comments
 (0)