8
8
import org .apache .bcel .generic .BasicType ;
9
9
import org .apache .bcel .generic .ObjectType ;
10
10
import org .apache .bcel .generic .Type ;
11
+ import org .apache .bcel .util .BCELComparator ;
11
12
12
13
import java .util .ArrayList ;
13
14
import java .util .Arrays ;
14
15
import java .util .HashMap ;
15
16
import java .util .HashSet ;
17
+ import java .util .LinkedList ;
16
18
import java .util .List ;
17
19
import java .util .Map ;
20
+ import java .util .Queue ;
18
21
import java .util .Set ;
19
22
20
23
/**
@@ -34,6 +37,8 @@ public class DtsApi {
34
37
35
38
public DtsApi () {
36
39
this .indent = 0 ;
40
+
41
+ overrideFieldComparator ();
37
42
}
38
43
39
44
public String generateDtsContent (List <JavaClass > javaClasses ) {
@@ -49,35 +54,63 @@ public String generateDtsContent(List<JavaClass> javaClasses) {
49
54
50
55
JavaClass currClass = javaClasses .get (i );
51
56
currentFileClassname = currClass .getClassName ();
57
+ boolean isInterface = currClass .isInterface ();
58
+ boolean isAbstract = currClass .isAbstract ();
52
59
53
60
this .indent = closePackage (this .prevClass , currClass );
54
61
this .indent = openPackage (this .prevClass , currClass );
55
62
56
63
String tabs = getTabs (this .indent );
57
64
58
65
JavaClass superClass = getSuperClass (currClass );
59
- String extendsLine = getExtendsLine (superClass );
66
+ List <JavaClass > interfaces = getInterfaces (currClass );
67
+ String extendsLine = getExtendsLine (superClass , interfaces );
60
68
61
69
if (getSimpleClassname (currClass ).equals ("AccessibilityDelegate" )) {
62
70
sbContent .appendln (tabs + "export class " + getFullClassNameConcatenated (currClass ) + extendsLine + " {" );
63
71
}
64
72
else {
65
- sbContent .appendln (tabs + "export class " + getSimpleClassname (currClass ) + extendsLine + " {" );
73
+ sbContent .appendln (tabs + "export" + ( isAbstract && ! isInterface ? " abstract " : " " ) + " class " + getSimpleClassname (currClass ) + extendsLine + " {" );
66
74
}
67
75
// 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 );
72
92
}
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
+ }
75
103
}
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 );
78
112
}
79
113
}
80
- // process member scope end
81
114
82
115
sbContent .appendln (tabs + "}" );
83
116
if (getSimpleClassname (currClass ).equals ("AccessibilityDelegate" )) {
@@ -102,12 +135,24 @@ else if(fom instanceof Method) {
102
135
return sbHeaders .toString () + sbContent .toString ();
103
136
}
104
137
105
- private String getExtendsLine (JavaClass superClass ) {
138
+ private String getExtendsLine (JavaClass superClass , List < JavaClass > interfaces ) {
106
139
if (superClass == null ) {
107
140
return "" ;
108
141
}
109
142
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 ;
111
156
}
112
157
113
158
private int closePackage (JavaClass prevClass , JavaClass currClass ) {
@@ -207,16 +252,109 @@ private int openPackage(JavaClass prevClass, JavaClass currClass) {
207
252
return indent ;
208
253
}
209
254
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
+ }
210
343
//method related
211
344
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
+ }
212
351
213
352
loadBaseMethods (clazz ); //loaded in "baseMethodNames" and "baseMethods"
214
353
215
354
String tabs = getTabs (this .indent + 1 );
216
355
217
356
cacheMethodBySignature (m ); //cached in "mapNameMethod"
218
357
219
- String name = m .getName ();
220
358
221
359
//generate base method content
222
360
if (baseMethodNames .contains (name )) {
@@ -490,4 +628,20 @@ private String getTabs(int count) {
490
628
String tabs = new String (new char [count ]).replace ("\0 " , "\t " );
491
629
return tabs ;
492
630
}
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
+ }
493
647
}
0 commit comments