Skip to content

Commit 2277d4b

Browse files
custom type naming (closes #57)
1 parent 05a70d4 commit 2277d4b

File tree

5 files changed

+116
-2
lines changed

5 files changed

+116
-2
lines changed

typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public class Settings {
2727
public String removeTypeNameSuffix = null;
2828
public String addTypeNamePrefix = null;
2929
public String addTypeNameSuffix = null;
30+
public Map<String, String> customTypeNaming = new LinkedHashMap<>();
3031
public DateMapping mapDate = DateMapping.asDate;
3132
public TypeProcessor customTypeProcessor = null;
3233
public boolean sortDeclarations = false;
@@ -56,6 +57,20 @@ public void loadOptionalAnnotations(ClassLoader classLoader, List<String> option
5657
}
5758
}
5859

60+
public static Map<String, String> convertToMap(List<String> mappings) {
61+
final Map<String, String> result = new LinkedHashMap<>();
62+
if (mappings != null) {
63+
for (String mapping : mappings) {
64+
final String[] values = mapping.split(":", 2);
65+
if (values.length < 2) {
66+
throw new RuntimeException("Invalid mapping format: " + mapping);
67+
}
68+
result.put(values[0].trim(), values[1].trim());
69+
}
70+
}
71+
return result;
72+
}
73+
5974
public void validate() {
6075
if (outputKind == null) {
6176
throw new RuntimeException("Required 'outputKind' parameter is not configured. " + seeLink());

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

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,43 @@ public Symbol getSyntheticSymbol(String name) {
3939
}
4040

4141
public void resolveSymbolNames(Settings settings) {
42-
// TODO check for conflicts
42+
final Map<String, List<Class<?>>> names = new LinkedHashMap<>();
4343
for (Map.Entry<Class<?>, Symbol> entry : symbols.entrySet()) {
4444
final Class<?> cls = entry.getKey();
4545
final Symbol symbol = entry.getValue();
46-
symbol.name = getMappedName(cls);
46+
final String name = getMappedName(cls);
47+
symbol.name = name;
48+
if (!names.containsKey(name)) {
49+
names.put(name, new ArrayList<Class<?>>());
50+
}
51+
names.get(name).add(cls);
52+
}
53+
reportConflicts(names);
54+
}
55+
56+
private static void reportConflicts(Map<String, List<Class<?>>> names) {
57+
boolean conflict = false;
58+
for (Map.Entry<String, List<Class<?>>> entry : names.entrySet()) {
59+
final String name = entry.getKey();
60+
final List<Class<?>> classes = entry.getValue();
61+
if (classes.size() > 1) {
62+
System.out.println(String.format("Multiple classes are mapped to '%s' name. Conflicting classes: %s", name, classes));
63+
conflict = true;
64+
}
65+
}
66+
if (conflict) {
67+
throw new NameConflictException("Multiple classes are mapped to the same name. You can use 'customTypeNaming' setting to resolve conflicts or exclude conflicting class if it was added accidentally.");
4768
}
4869
}
4970

5071
private String getMappedName(Class<?> cls) {
5172
if (cls == null) {
5273
return null;
5374
}
75+
final String customName = settings.customTypeNaming.get(cls.getName());
76+
if (customName != null) {
77+
return customName;
78+
}
5479
String name = cls.getSimpleName();
5580
if (settings.removeTypeNamePrefix != null && name.startsWith(settings.removeTypeNamePrefix)) {
5681
name = name.substring(settings.removeTypeNamePrefix.length(), name.length());
@@ -67,4 +92,26 @@ private String getMappedName(Class<?> cls) {
6792
return name;
6893
}
6994

95+
96+
public static class NameConflictException extends RuntimeException {
97+
98+
private static final long serialVersionUID = 1L;
99+
100+
public NameConflictException() {
101+
}
102+
103+
public NameConflictException(String message) {
104+
super(message);
105+
}
106+
107+
public NameConflictException(String message, Throwable cause) {
108+
super(message, cause);
109+
}
110+
111+
public NameConflictException(Throwable cause) {
112+
super(cause);
113+
}
114+
115+
}
116+
70117
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
package cz.habarta.typescript.generator;
3+
4+
import cz.habarta.typescript.generator.compiler.SymbolTable;
5+
import java.util.LinkedHashMap;
6+
import org.junit.Assert;
7+
import org.junit.Test;
8+
9+
10+
public class NamingTest {
11+
12+
@Test(expected = SymbolTable.NameConflictException.class)
13+
public void testConflictReport() {
14+
final Settings settings = TestUtils.settings();
15+
new TypeScriptGenerator(settings).generateTypeScript(Input.from(A.ConflictingClass.class, B.ConflictingClass.class));
16+
}
17+
18+
@Test
19+
public void testConflictResolved() {
20+
final Settings settings = TestUtils.settings();
21+
settings.customTypeNaming = new LinkedHashMap<>();
22+
settings.customTypeNaming.put("cz.habarta.typescript.generator.NamingTest$A$ConflictingClass", "A$ConflictingClass");
23+
settings.customTypeNaming.put("cz.habarta.typescript.generator.NamingTest$B$ConflictingClass", "B$ConflictingClass");
24+
final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(A.ConflictingClass.class, B.ConflictingClass.class));
25+
Assert.assertTrue(output.contains("A$ConflictingClass"));
26+
Assert.assertTrue(output.contains("B$ConflictingClass"));
27+
}
28+
29+
private static class A {
30+
private static class ConflictingClass {
31+
public String conflictingProperty;
32+
}
33+
}
34+
35+
private static class B {
36+
private static class ConflictingClass {
37+
public String conflictingProperty;
38+
}
39+
}
40+
41+
}

typescript-generator-gradle-plugin/src/main/java/cz/habarta/typescript/generator/gradle/GenerateTask.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public class GenerateTask extends DefaultTask {
2727
public String removeTypeNameSuffix;
2828
public String addTypeNamePrefix;
2929
public String addTypeNameSuffix;
30+
public List<String> customTypeNaming;
3031
public DateMapping mapDate;
3132
public String customTypeProcessor;
3233
public boolean sortDeclarations;
@@ -75,6 +76,7 @@ public void generate() throws Exception {
7576
settings.removeTypeNameSuffix = removeTypeNameSuffix;
7677
settings.addTypeNamePrefix = addTypeNamePrefix;
7778
settings.addTypeNameSuffix = addTypeNameSuffix;
79+
settings.customTypeNaming = Settings.convertToMap(customTypeNaming);
7880
settings.mapDate = mapDate;
7981
settings.loadCustomTypeProcessor(classLoader, customTypeProcessor);
8082
settings.sortDeclarations = sortDeclarations;

typescript-generator-maven-plugin/src/main/java/cz/habarta/typescript/generator/maven/GenerateMojo.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ public class GenerateMojo extends AbstractMojo {
129129
@Parameter
130130
private String addTypeNameSuffix;
131131

132+
/**
133+
* Specifies custom TypeScript name for Java classes.
134+
* Multiple mappings can be specified, each using this format: "javaClassName:typescriptName".
135+
* This takes precedence over other naming settings.
136+
*/
137+
@Parameter
138+
private List<String> customTypeNaming;
139+
132140
/**
133141
* Specifies how {@link java.util.Date} will be mapped.
134142
* Supported values are 'asDate', 'asNumber, 'asString'.
@@ -229,6 +237,7 @@ public void execute() {
229237
settings.removeTypeNameSuffix = removeTypeNameSuffix;
230238
settings.addTypeNamePrefix = addTypeNamePrefix;
231239
settings.addTypeNameSuffix = addTypeNameSuffix;
240+
settings.customTypeNaming = Settings.convertToMap(customTypeNaming);
232241
settings.mapDate = mapDate;
233242
settings.loadCustomTypeProcessor(classLoader, customTypeProcessor);
234243
settings.sortDeclarations = sortDeclarations;

0 commit comments

Comments
 (0)