Skip to content

Commit a8c7f11

Browse files
authored
Merge pull request #779 from NativeScript/pete/fix-sbg-abstract-class-methods
Fix SBG
2 parents ce77388 + 6ca81d9 commit a8c7f11

File tree

9 files changed

+115
-53
lines changed

9 files changed

+115
-53
lines changed

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

Lines changed: 69 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
import java.io.IOException;
88
import java.io.InputStreamReader;
99
import java.io.PrintStream;
10+
import java.nio.file.Files;
11+
import java.nio.file.Paths;
1012
import java.util.ArrayDeque;
1113
import java.util.ArrayList;
1214
import java.util.Arrays;
1315
import java.util.HashMap;
1416
import java.util.HashSet;
1517
import java.util.List;
1618
import java.util.Map;
19+
import java.util.Objects;
1720
import java.util.Queue;
1821
import java.util.Set;
1922
import java.util.jar.JarInputStream;
@@ -24,6 +27,8 @@
2427
import org.apache.bcel.classfile.Method;
2528
import org.apache.bcel.generic.Type;
2629

30+
import javafx.util.Pair;
31+
2732
public class Generator {
2833
private static final String JAVA_EXT = ".java";
2934

@@ -45,7 +50,6 @@ public Generator(String outputDir, String[] libs, boolean throwOnError) throws I
4550
this.classes = readClasses(libs, throwOnError);
4651
}
4752

48-
4953
public void writeBindings(String filename) throws IOException, ClassNotFoundException {
5054
Binding[] bindings = generateBindings(filename);
5155
Set<File> writtenFiles = new HashSet<File>();
@@ -54,8 +58,15 @@ public void writeBindings(String filename) throws IOException, ClassNotFoundExce
5458
try (PrintStream ps = new PrintStream(b.getFile())) {
5559
ps.append(b.getContent());
5660
}
61+
// A file with that name has already been written
5762
} else {
58-
throw new IOException("File already exists. This may lead to undesired behavior.\nPlease change the name of one of the extended classes.\n" + b.getFile());
63+
// Compare text contents for equality
64+
String content = new String(Files.readAllBytes(Paths.get(b.getFile().toString())));
65+
if (content.equals(b.getContent())) {
66+
System.out.println("Warning: File already exists. This could mean the same code has been parsed more than once from two or more different files.");
67+
} else {
68+
throw new IOException("File already exists. This may lead to undesired behavior.\nPlease change the name of one of the extended classes.\n" + b.getFile());
69+
}
5970
}
6071
}
6172
}
@@ -186,51 +197,32 @@ private String getNormalizedName(String filename) {
186197
return sb.toString();
187198
}
188199

189-
private Map<String, List<Method>> getPublicApi(JavaClass clazz) throws ClassNotFoundException {
190-
Map<String, List<Method>> api = new HashMap<String, List<Method>>();
200+
private Map<String, MethodGroup> getPublicApi(JavaClass clazz) throws ClassNotFoundException {
201+
Map<String, MethodGroup> api = new HashMap<>();
191202
JavaClass currentClass = clazz;
192203
String clazzName = clazz.getClassName();
193204
while (true) {
194205
String currentClassname = currentClass.getClassName();
195206

196-
boolean shouldCollectMethods = !(!clazzName.equals(currentClassname) && currentClass.isAbstract());
197-
198-
if (shouldCollectMethods || currentClass.isInterface()) {
199-
// Don't include abstract parent class's methods to avoid compilation issues
200-
// where a child class has 2 methods, of the same type, with just a
201-
// return type/parameter type that differs by being of a superclass of the class being extended.
202-
// see Test testCanCompileBindingClassExtendingAnExtendedClassWithMethodsWithTheSameSignature
203-
List<Method> methods = new ArrayList<Method>();
204-
for (Method m : currentClass.getMethods()) {
205-
methods.add(m);
206-
}
207-
208-
// System.out.println("SBG: getPublicApi:collectInterfaceMethods classname: " + currentClassname);
207+
List<Method> methods = new ArrayList<Method>();
208+
for (Method m : currentClass.getMethods()) {
209+
methods.add(m);
210+
}
209211

210-
collectInterfaceMethods(clazz, methods);
211-
for (Method m : methods) {
212-
if (!m.isSynthetic() && (m.isPublic() || m.isProtected()) && !m.isStatic()) {
213-
String name = m.getName();
212+
collectInterfaceMethods(clazz, methods);
213+
for (Method m : methods) {
214+
if (!m.isSynthetic() && (m.isPublic() || m.isProtected()) && !m.isStatic()) {
215+
String name = m.getName();
214216

215-
List<Method> methodGroup;
216-
if (api.containsKey(name)) {
217-
methodGroup = api.get(name);
218-
} else {
219-
methodGroup = new ArrayList<Method>();
220-
api.put(name, methodGroup);
221-
}
222-
boolean found = false;
223-
String methodSig = m.getSignature();
224-
for (Method m1 : methodGroup) {
225-
found = methodSig.equals(m1.getSignature());
226-
if (found) {
227-
break;
228-
}
229-
}
230-
if (!found) {
231-
methodGroup.add(m);
232-
}
217+
MethodGroup methodGroup;
218+
if (api.containsKey(name)) {
219+
methodGroup = api.get(name);
220+
} else {
221+
methodGroup = new MethodGroup(currentClassname);
222+
api.put(name, methodGroup);
233223
}
224+
225+
methodGroup.add(currentClassname, m);
234226
}
235227
}
236228

@@ -331,7 +323,7 @@ private void writeBinding(Writer w, DataRow dataRow, JavaClass clazz, String pac
331323
String[] implInterfaces = dataRow.getInterfaces();
332324
collectImplementedInterfaces(implInterfaces, clazz);
333325

334-
Map<String, List<Method>> api = getPublicApi(clazz);
326+
Map<String, MethodGroup> api = getPublicApi(clazz);
335327

336328
w.writeln("package " + packageName + ";");
337329
w.writeln();
@@ -438,7 +430,7 @@ private void writeBinding(Writer w, DataRow dataRow, JavaClass clazz, String pac
438430
collectInterfaceMethods(clazz, interfaceMethods);
439431
for (String methodName : dataRow.getMethods()) {
440432
if (api.containsKey(methodName)) {
441-
List<Method> methodGroup = api.get(methodName);
433+
List<Method> methodGroup = api.get(methodName).getList();
442434
for (Method m : methodGroup) {
443435
boolean isInterfaceMethod = false;
444436
if (interfaceMethods.contains(m)) {
@@ -719,4 +711,40 @@ private JavaClass getClass(String className) throws ClassNotFoundException {
719711

720712
return clazz;
721713
}
714+
715+
private class MethodGroup {
716+
private List<Method> methods;
717+
private String latestInheritorClassName;
718+
719+
public MethodGroup(String forClass) {
720+
this.methods = new ArrayList<>();
721+
this.latestInheritorClassName = forClass;
722+
}
723+
724+
public void add(String methodClassname, Method m) {
725+
boolean found = false;
726+
727+
String methodSig = m.getSignature();
728+
for (Method m1 : this.methods) {
729+
found = methodSig.equals(m1.getSignature());
730+
if (found) {
731+
break;
732+
}
733+
}
734+
735+
if (!found) {
736+
// Only add method to API if method hasn't already been added by an inheritor of
737+
// the current class
738+
if (!methodClassname.equals(this.latestInheritorClassName)) {
739+
return;
740+
}
741+
742+
this.methods.add(m);
743+
}
744+
}
745+
746+
public List<Method> getList() {
747+
return this.methods;
748+
}
749+
}
722750
}

android-static-binding-generator/project/staticbindinggenerator/src/test/java/com/example/ListView.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package com.example;
22

3-
/**
4-
* Created by pkanev on 4/27/2017.
5-
*/
6-
73
public class ListView extends View {
84
public ListView createView() {
95
return new ListView();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.example;
2+
3+
public abstract class MyAbstractClass {
4+
String className;
5+
6+
public MyAbstractClass(String name) {
7+
this.className = name;
8+
}
9+
10+
public abstract void abstractMethod();
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.example;
2+
3+
public abstract class MyAbstractClass2 extends MyAbstractClass {
4+
public MyAbstractClass2() {
5+
super("MyNotSoAbstractClass");
6+
}
7+
}
Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
package com.example;
22

3-
/**
4-
* Created by slavchev on 7/6/2016.
5-
*/
63
public class MyClass {
74
}

android-static-binding-generator/project/staticbindinggenerator/src/test/java/com/example/View.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package com.example;
22

3-
/**
4-
* Created by pkanev on 4/27/2017.
5-
*/
6-
73
public abstract class View {
84
public View createView() {
95
return null;

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,6 +1,7 @@
11
package org.nativescript.staticbindinggenerator.test;
22

33
import com.example.ListView;
4+
import com.example.MyAbstractClass2;
45
import com.example.MyInterface;
56

67
import org.apache.commons.io.IOUtils;
@@ -129,4 +130,29 @@ public void testCanCompileBindingClassExtendingAnExtendedClassWithMethodsWithThe
129130
Assert.assertNotNull(ComplexClass);
130131
Assert.assertEquals(4, ComplexClass.getDeclaredMethods().length); // 1 + constructor + (equals + hashcode)
131132
}
133+
134+
@Test
135+
public void testCanCompileBindingClassExtendingAnAbstractClassThatExtendsAbstractClass() throws Exception {
136+
URL u = MyAbstractClass2.class.getResource('/' + MyAbstractClass2.class.getName().replace('.', '/') + ".class");
137+
File f = new File(u.toURI()).getParentFile().getParentFile().getParentFile();
138+
139+
String dataRowString = "com.example.MyAbstractClass2*_fapp_l9_c29__*abstractMethod*com.example.com.example.MyExtendedClass**";
140+
DataRow dataRow = new DataRow(dataRowString);
141+
142+
System.out.println(dataRowString);
143+
144+
String outputDir = null;
145+
String[] libs = {runtimePath, f.getAbsolutePath()};
146+
Generator generator = new Generator(outputDir, libs);
147+
Binding binding = generator.generateBinding(dataRow);
148+
149+
StringBuffer sourceCode = new StringBuffer();
150+
sourceCode.append(binding.getContent());
151+
152+
Iterable<String> options = new ArrayList<String>(Arrays.asList("-cp", dependenciesDir));
153+
Class<?> ComplexClass = InMemoryJavaCompiler.compile(binding.getClassname(), sourceCode.toString(), options);
154+
155+
// class compiles, meaning abstract method of super-super class is extended properly
156+
Assert.assertNotNull(ComplexClass);
157+
}
132158
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.example.MyAbstractClass2*_fapp_l9_c29__*abstractMethod*com.example.com.example.MyExtendedClass**
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"com.example.ListView*_fapp_l9_c29__*createView*com.example.MyListView**"
1+
com.example.ListView*_fapp_l9_c29__*createView*com.example.MyListView**

0 commit comments

Comments
 (0)