Skip to content

Commit af5eed6

Browse files
authored
Merge pull request #10 from NativeScript/pete/improve-interface-generation
Pete/improve interface generation
2 parents 375e92f + 26a0870 commit af5eed6

File tree

2 files changed

+174
-14
lines changed

2 files changed

+174
-14
lines changed

dts-generator/src/main/java/com/telerik/Main.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ public class Main {
1616
public static void main(String[] args) throws Exception {
1717
InputParameters inputParameters = parseCommand(args);
1818

19+
long startTime = System.currentTimeMillis();
20+
1921
new Generator().start(inputParameters);
22+
23+
long stopTime = System.currentTimeMillis();
24+
long elapsedTime = stopTime - startTime;
25+
System.out.println("Generation of definitions took " + elapsedTime + "ms.");
2026
}
2127

2228
public static InputParameters parseCommand(String[] args) {

dts-generator/src/main/java/com/telerik/dts/DtsApi.java

Lines changed: 168 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
import org.apache.bcel.generic.BasicType;
99
import org.apache.bcel.generic.ObjectType;
1010
import org.apache.bcel.generic.Type;
11+
import org.apache.bcel.util.BCELComparator;
1112

1213
import java.util.ArrayList;
1314
import java.util.Arrays;
1415
import java.util.HashMap;
1516
import java.util.HashSet;
17+
import java.util.LinkedList;
1618
import java.util.List;
1719
import java.util.Map;
20+
import java.util.Queue;
1821
import java.util.Set;
1922

2023
/**
@@ -34,6 +37,8 @@ public class DtsApi {
3437

3538
public DtsApi() {
3639
this.indent = 0;
40+
41+
overrideFieldComparator();
3742
}
3843

3944
public String generateDtsContent(List<JavaClass> javaClasses) {
@@ -49,35 +54,63 @@ public String generateDtsContent(List<JavaClass> javaClasses) {
4954

5055
JavaClass currClass = javaClasses.get(i);
5156
currentFileClassname = currClass.getClassName();
57+
boolean isInterface = currClass.isInterface();
58+
boolean isAbstract = currClass.isAbstract();
5259

5360
this.indent = closePackage(this.prevClass, currClass);
5461
this.indent = openPackage(this.prevClass, currClass);
5562

5663
String tabs = getTabs(this.indent);
5764

5865
JavaClass superClass = getSuperClass(currClass);
59-
String extendsLine = getExtendsLine(superClass);
66+
List<JavaClass> interfaces = getInterfaces(currClass);
67+
String extendsLine = getExtendsLine(superClass, interfaces);
6068

6169
if(getSimpleClassname(currClass).equals("AccessibilityDelegate")) {
6270
sbContent.appendln(tabs + "export class " + getFullClassNameConcatenated(currClass) + extendsLine + " {");
6371
}
6472
else {
65-
sbContent.appendln(tabs + "export class " + getSimpleClassname(currClass) + extendsLine + " {");
73+
sbContent.appendln(tabs + "export" + (isAbstract && !isInterface ? " abstract " : " ") + "class " + getSimpleClassname(currClass) + extendsLine + " {");
6674
}
6775
// process member scope
68-
List<FieldOrMethod> foms = getMembers(currClass);
69-
for(FieldOrMethod fom : foms) {
70-
if(fom instanceof Field) {
71-
processField((Field)fom, currClass);
76+
77+
// process constructors for interfaces
78+
if(isInterface) {
79+
List<JavaClass> allInterfaces = getAllInterfaces(currClass);
80+
81+
List<Method> allInterfacesMethods = getAllInterfacesMethods(allInterfaces);
82+
Set<Field> allInterfaceFields = getAllInterfacesFields(allInterfaces);
83+
84+
processInterfaceConstructor(currClass, allInterfacesMethods);
85+
86+
for(Method m : allInterfacesMethods) {
87+
processMethod(m, currClass);
88+
}
89+
90+
for(Field f : allInterfaceFields) {
91+
processField(f, currClass);
7292
}
73-
else if(fom instanceof Method) {
74-
processMethod((Method)fom, currClass);
93+
} else {
94+
List<FieldOrMethod> foms = getMembers(currClass);
95+
for (FieldOrMethod fom : foms) {
96+
if (fom instanceof Field) {
97+
processField((Field) fom, currClass);
98+
} else if (fom instanceof Method) {
99+
processMethod((Method) fom, currClass);
100+
} else {
101+
throw new IllegalArgumentException("Argument is not method or field");
102+
}
75103
}
76-
else {
77-
throw new IllegalArgumentException("Argument is not method or field");
104+
// process member scope end
105+
}
106+
107+
if(isAbstract && !isInterface) {
108+
List<JavaClass> allInterfaces = getAllInterfaces(currClass);
109+
List<Method> allInterfacesMethods = getAllInterfacesMethods(allInterfaces);
110+
for(Method m : allInterfacesMethods) {
111+
processMethod(m, currClass);
78112
}
79113
}
80-
// process member scope end
81114

82115
sbContent.appendln(tabs + "}");
83116
if(getSimpleClassname(currClass).equals("AccessibilityDelegate")) {
@@ -102,12 +135,24 @@ else if(fom instanceof Method) {
102135
return sbHeaders.toString() + sbContent.toString();
103136
}
104137

105-
private String getExtendsLine(JavaClass superClass) {
138+
private String getExtendsLine(JavaClass superClass, List<JavaClass> interfaces) {
106139
if(superClass == null) {
107140
return "";
108141
}
109142

110-
return " extends " + superClass.getClassName().replaceAll("\\$", "\\.");
143+
StringBuilder implementsSegmentSb = new StringBuilder();
144+
String implementsSegment = "";
145+
if(interfaces.size() > 0) {
146+
implementsSegmentSb.append(" implements ");
147+
148+
for(JavaClass clazz : interfaces) {
149+
implementsSegmentSb.append(clazz.getClassName().replaceAll("\\$", "\\.") + ", ");
150+
}
151+
152+
implementsSegment = implementsSegmentSb.substring(0, implementsSegmentSb.lastIndexOf(","));
153+
}
154+
155+
return " extends " + superClass.getClassName().replaceAll("\\$", "\\.") + implementsSegment;
111156
}
112157

113158
private int closePackage(JavaClass prevClass, JavaClass currClass) {
@@ -207,16 +252,109 @@ private int openPackage(JavaClass prevClass, JavaClass currClass) {
207252
return indent;
208253
}
209254

255+
private void processInterfaceConstructor(JavaClass classInterface, List<Method> allInterfacesMethods) {
256+
String tabs = getTabs(this.indent + 1);
257+
258+
generateInterfaceConstructorContent(classInterface, tabs, allInterfacesMethods);
259+
}
260+
261+
private void generateInterfaceConstructorContent(JavaClass classInterface, String tabs, List<Method> methods) {
262+
generateInterfaceConstructorCommentBlock(classInterface, tabs);
263+
264+
sbContent.appendln(tabs + "public constructor(implementation: {");
265+
266+
for (Method m : methods) {
267+
sbContent.append(getTabs(this.indent + 2) + getMethodName(m) + getMethodParamSignature(classInterface, m));
268+
String bmSig = "";
269+
if (!isConstructor(m)) {
270+
bmSig += ": " + getTypeScriptTypeFromJavaType(classInterface, m.getReturnType());
271+
}
272+
sbContent.appendln(bmSig + ";");
273+
}
274+
275+
sbContent.appendln(tabs + "});");
276+
}
277+
278+
private void generateInterfaceConstructorCommentBlock(JavaClass classInterface, String tabs) {
279+
sbContent.appendln(tabs + "/**");
280+
sbContent.appendln(tabs + " * Constructs a new instance of the " + classInterface.getClassName() + " interface with the provided implementation.");
281+
// sbContent.appendln(tabs + " * @param implementation - allows implementor to define their own logic for all public methods."); // <- causes too much noise
282+
sbContent.appendln(tabs + " */");
283+
}
284+
285+
private List<JavaClass> getAllInterfaces(JavaClass classInterface) {
286+
ArrayList<JavaClass> interfaces = new ArrayList<>();
287+
288+
Queue<JavaClass> classQueue = new LinkedList<>();
289+
classQueue.add(classInterface);
290+
291+
while(!classQueue.isEmpty()) {
292+
JavaClass clazz = classQueue.poll();
293+
294+
interfaces.add(clazz);
295+
296+
classQueue.addAll(getInterfaces(clazz));
297+
}
298+
299+
return interfaces;
300+
}
301+
302+
private List<JavaClass> getInterfaces(JavaClass classInterface) {
303+
List<JavaClass> interfaces = new ArrayList<>();
304+
305+
String[] interfaceNames = classInterface.getInterfaceNames();
306+
for(String intface : interfaceNames) {
307+
JavaClass clazz1 = ClassRepo.findClass(intface);
308+
String className = clazz1.getClassName();
309+
310+
// TODO: Pete: Hardcoded until we figure out how to go around the 'type incompatible with Object' issue
311+
if (className.equals("java.util.Iterator") ||
312+
className.equals("android.animation.TypeEvaluator") ||
313+
className.equals("java.lang.Comparable")) {
314+
continue;
315+
}
316+
317+
interfaces.add(clazz1);
318+
}
319+
320+
return interfaces;
321+
}
322+
323+
private List<Method> getAllInterfacesMethods(List<JavaClass> interfaces) {
324+
ArrayList<Method> allInterfacesMethods = new ArrayList<>();
325+
326+
for(JavaClass clazz : interfaces) {
327+
Method[] intfaceMethods = clazz.getMethods();
328+
allInterfacesMethods.addAll(Arrays.asList(intfaceMethods));
329+
}
330+
331+
return allInterfacesMethods;
332+
}
333+
334+
private Set<Field> getAllInterfacesFields(List<JavaClass> interfaces) {
335+
HashSet<Field> allInterfacesFields = new HashSet<>();
336+
337+
for(JavaClass clazz : interfaces) {
338+
allInterfacesFields.addAll(Arrays.asList(clazz.getFields()));
339+
}
340+
341+
return allInterfacesFields;
342+
}
210343
//method related
211344
private void processMethod(Method m, JavaClass clazz) {
345+
String name = m.getName();
346+
347+
// TODO: Pete: won't generate static initializers as invalid typescript properties
348+
if(clazz.isInterface() && name.equals("<clinit>")) {
349+
return;
350+
}
212351

213352
loadBaseMethods(clazz); //loaded in "baseMethodNames" and "baseMethods"
214353

215354
String tabs = getTabs(this.indent + 1);
216355

217356
cacheMethodBySignature(m); //cached in "mapNameMethod"
218357

219-
String name = m.getName();
220358

221359
//generate base method content
222360
if (baseMethodNames.contains(name)) {
@@ -490,4 +628,20 @@ private String getTabs(int count) {
490628
String tabs = new String(new char[count]).replace("\0", "\t");
491629
return tabs;
492630
}
631+
632+
private void overrideFieldComparator() {
633+
BCELComparator cmp = Field.getComparator();
634+
635+
Field.setComparator(new BCELComparator() {
636+
@Override
637+
public boolean equals(Object o, Object o1) {
638+
return ((Field)o).getName().equals(((Field) o1).getName());
639+
}
640+
641+
@Override
642+
public int hashCode(Object o) {
643+
return cmp.hashCode(o);
644+
}
645+
});
646+
}
493647
}

0 commit comments

Comments
 (0)