Skip to content

Commit ce5d00f

Browse files
authored
Merge pull request #754 from NativeScript/pete/fix-sbg
Fix SBG (#753) and string replacement
2 parents df627ec + c2d02b4 commit ce5d00f

File tree

5 files changed

+98
-28
lines changed

5 files changed

+98
-28
lines changed

android-static-binding-generator/project/staticbindinggenerator/src/main/java/org/nativescript/staticbindinggenerator/Generator.java

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.io.PrintStream;
1010
import java.util.ArrayDeque;
1111
import java.util.ArrayList;
12+
import java.util.Arrays;
1213
import java.util.HashMap;
1314
import java.util.HashSet;
1415
import java.util.List;
@@ -141,6 +142,9 @@ private Binding[] processRows(List<DataRow> rows) throws IOException {
141142
String classname = dataRow.getBaseClassname();
142143
boolean isJavaExtend = classes.containsKey(classname);
143144
if (isJavaExtend) {
145+
146+
// System.out.println("SBG: DataRow: baseClassName: " + classname + ", suffix: " + dataRow.getSuffix() + ", interfaces: " + String.join(", ", Arrays.asList(dataRow.getInterfaces())) + ", jsFileName: " + dataRow.getJsFilename());
147+
144148
Binding binding = generateBinding(dataRow, interfaceNames);
145149

146150
if (binding != null) {
@@ -187,42 +191,56 @@ private String getNormalizedName(String filename) {
187191
private Map<String, List<Method>> getPublicApi(JavaClass clazz) {
188192
Map<String, List<Method>> api = new HashMap<String, List<Method>>();
189193
JavaClass currentClass = clazz;
194+
String clazzName = clazz.getClassName();
190195
while (true) {
191196
String currentClassname = currentClass.getClassName();
192-
List<Method> methods = new ArrayList<Method>();
193-
for (Method m : currentClass.getMethods()) {
194-
methods.add(m);
195-
}
196-
collectInterfaceMethods(clazz, methods);
197-
for (Method m : methods) {
198-
if (!m.isSynthetic() && (m.isPublic() || m.isProtected()) && !m.isStatic()) {
199-
String name = m.getName();
200-
201-
List<Method> methodGroup;
202-
if (api.containsKey(name)) {
203-
methodGroup = api.get(name);
204-
} else {
205-
methodGroup = new ArrayList<Method>();
206-
api.put(name, methodGroup);
207-
}
208-
boolean found = false;
209-
String methodSig = m.getSignature();
210-
for (Method m1 : methodGroup) {
211-
found = methodSig.equals(m1.getSignature());
212-
if (found) {
213-
break;
197+
198+
boolean shouldCollectMethods = !(!clazzName.equals(currentClassname) && currentClass.isAbstract());
199+
200+
if (shouldCollectMethods || currentClass.isInterface()) {
201+
// Don't include abstract parent class's methods to avoid compilation issues
202+
// where a child class has 2 methods, of the same type, with just a
203+
// return type/parameter type that differs by being of a superclass of the class being extended.
204+
// see Test testCanCompileBindingClassExtendingAnExtendedClassWithMethodsWithTheSameSignature
205+
List<Method> methods = new ArrayList<Method>();
206+
for (Method m : currentClass.getMethods()) {
207+
methods.add(m);
208+
}
209+
210+
// System.out.println("SBG: getPublicApi:collectInterfaceMethods classname: " + currentClassname);
211+
212+
collectInterfaceMethods(clazz, methods);
213+
for (Method m : methods) {
214+
if (!m.isSynthetic() && (m.isPublic() || m.isProtected()) && !m.isStatic()) {
215+
String name = m.getName();
216+
217+
List<Method> methodGroup;
218+
if (api.containsKey(name)) {
219+
methodGroup = api.get(name);
220+
} else {
221+
methodGroup = new ArrayList<Method>();
222+
api.put(name, methodGroup);
223+
}
224+
boolean found = false;
225+
String methodSig = m.getSignature();
226+
for (Method m1 : methodGroup) {
227+
found = methodSig.equals(m1.getSignature());
228+
if (found) {
229+
break;
230+
}
231+
}
232+
if (!found) {
233+
methodGroup.add(m);
214234
}
215-
}
216-
if (!found) {
217-
methodGroup.add(m);
218235
}
219236
}
220237
}
221238

222239
if (currentClassname.equals("java.lang.Object")) {
223240
break;
224241
} else {
225-
currentClass = classes.get(currentClass.getSuperclassName());
242+
String superClassName = currentClass.getSuperclassName();
243+
currentClass = classes.get(superClassName.replace('$', '.'));
226244
}
227245
}
228246
return api;
@@ -640,6 +658,7 @@ private void writeType(Type t, Writer w) {
640658

641659
private void collectInterfaceMethods(JavaClass clazz, List<Method> methods) {
642660
JavaClass currentClass = clazz;
661+
643662
while (true) {
644663
String currentClassname = currentClass.getClassName();
645664

@@ -663,7 +682,8 @@ private void collectInterfaceMethods(JavaClass clazz, List<Method> methods) {
663682
if (currentClassname.equals("java.lang.Object")) {
664683
break;
665684
} else {
666-
currentClass = classes.get(currentClass.getSuperclassName());
685+
String superClassName = currentClass.getSuperclassName();
686+
currentClass = classes.get(superClassName.replace('$', '.'));
667687
}
668688
}
669689
}
@@ -686,7 +706,8 @@ private boolean isApplicationClass(JavaClass clazz, Map<String, JavaClass> class
686706
break;
687707
}
688708

689-
currentClass = classes.get(currentClass.getSuperclassName());
709+
String superClassName = currentClass.getSuperclassName();
710+
currentClass = classes.get(superClassName.replace('$', '.'));
690711
}
691712

692713
return isApplicationClass;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.example;
2+
3+
/**
4+
* Created by pkanev on 4/27/2017.
5+
*/
6+
7+
public class ListView extends View {
8+
public ListView createView() {
9+
return new ListView();
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.example;
2+
3+
/**
4+
* Created by pkanev on 4/27/2017.
5+
*/
6+
7+
public abstract class View {
8+
public View createView() {
9+
return null;
10+
}
11+
}

android-static-binding-generator/project/staticbindinggenerator/src/test/java/org/nativescript/staticbindinggenerator/test/GeneratorTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.nativescript.staticbindinggenerator.test;
22

3+
import com.example.ListView;
34
import com.example.MyInterface;
45

56
import org.apache.commons.io.IOUtils;
@@ -103,4 +104,29 @@ public void testCanCompileBindingClassImplementingMultipleInterfaces() throws Ex
103104
Assert.assertNotNull(ComplexClass);
104105
Assert.assertEquals(5, ComplexClass.getInterfaces().length); // 4 + 1 (hashcodeprovider)
105106
}
107+
108+
@Test
109+
public void testCanCompileBindingClassExtendingAnExtendedClassWithMethodsWithTheSameSignature() throws Exception {
110+
URL u = ListView.class.getResource('/' + ListView.class.getName().replace('.', '/') + ".class");
111+
File f = new File(u.toURI()).getParentFile().getParentFile().getParentFile();
112+
113+
String dataRowString = "com.example.ListView*_fapp_l9_c29__*createView*com.example.MyListView**";
114+
DataRow dataRow = new DataRow(dataRowString);
115+
116+
System.out.println(dataRowString);
117+
118+
String outputDir = null;
119+
String[] libs = {runtimePath, f.getAbsolutePath()};
120+
Generator generator = new Generator(outputDir, libs);
121+
Binding binding = generator.generateBinding(dataRow);
122+
123+
StringBuffer sourceCode = new StringBuffer();
124+
sourceCode.append(binding.getContent());
125+
126+
Iterable<String> options = new ArrayList<String>(Arrays.asList("-cp", dependenciesDir));
127+
Class<?> ComplexClass = InMemoryJavaCompiler.compile(binding.getClassname(), sourceCode.toString(), options);
128+
129+
Assert.assertNotNull(ComplexClass);
130+
Assert.assertEquals(4, ComplexClass.getDeclaredMethods().length); // 1 + constructor + (equals + hashcode)
131+
}
106132
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"com.example.ListView*_fapp_l9_c29__*createView*com.example.MyListView**"

0 commit comments

Comments
 (0)