From 2dcaa053a0233fef6652943d93755b2bc4cc10d3 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 27 Sep 2016 17:59:07 +0200 Subject: [PATCH] bind: preserve no-arg Java constructors When the Java class parser began culling unused constructors, the logic for determining whether a given Java class has a no-arg constructor broke when the no-arg constructor is culled. Add an explicit field for tracking the no-arg constructor property. Change-Id: Ib68929ae1108bd6fa1fd23de1d134332eb0d97a2 Reviewed-on: https://go-review.googlesource.com/29875 Reviewed-by: Hyang-Ah Hana Kim --- bind/genjava.go | 22 +++++++++------------- bind/testdata/classes.java.c.golden | 9 +++++++++ bind/testdata/classes.java.golden | 6 ++++++ bind/testpkg/javapkg/classes.go | 4 ++++ internal/importers/java/java.go | 11 +++++++++-- 5 files changed, 37 insertions(+), 15 deletions(-) diff --git a/bind/genjava.go b/bind/genjava.go index 2b86b98..c0b1569 100644 --- a/bind/genjava.go +++ b/bind/genjava.go @@ -34,8 +34,8 @@ type javaClassInfo struct { // All Java classes and interfaces this class extends and implements. supers []*java.Class methods map[string]*java.Func - // Does the extended class include a noarg constructor - hasNoargCon bool + // Does the class need a default no-arg constructor + genNoargCon bool // Constructors for the type, on the form // func New(...) *Type cons []*types.Func @@ -57,7 +57,7 @@ func (g *JavaGen) Init(classes []*java.Class) { } inf := &javaClassInfo{ methods: make(map[string]*java.Func), - hasNoargCon: true, // java.lang.Object has a noarg constructor + genNoargCon: true, // java.lang.Object has a no-arg constructor } for _, n := range classes { cls := g.clsMap[n] @@ -76,13 +76,7 @@ func (g *JavaGen) Init(classes []*java.Class) { g.errorf("%s embeds final Java class %s", s.obj, cls.Name) } inf.extends = cls - inf.hasNoargCon = false - for _, f := range cls.Funcs { - if f.Constructor && len(f.Params) == 0 { - inf.hasNoargCon = true - break - } - } + inf.genNoargCon = cls.HasNoArgCon } } g.jstructs[s.obj] = inf @@ -91,6 +85,8 @@ func (g *JavaGen) Init(classes []*java.Class) { if t := g.constructorType(f); t != nil { jinf := g.jstructs[t] if jinf != nil { + sig := f.Type().(*types.Signature) + jinf.genNoargCon = jinf.genNoargCon && sig.Params().Len() > 0 jinf.cons = append(jinf.cons, f) } } @@ -181,7 +177,7 @@ func (g *JavaGen) genStruct(s structInfo) { } g.genConstructor(f, n) } - if jinf.hasNoargCon { + if jinf.genNoargCon { // Generate constructor for Go instantiated instances. g.Printf("%s(Seq.Ref ref) { this.ref = ref; }\n\n", n) // Generate default no-arg constructor @@ -1279,7 +1275,7 @@ func (g *JavaGen) GenC() error { if jinf, ok := g.jstructs[s.obj]; ok { // Leave the class and constructor NULL for Java classes with no // default constructor. - if !jinf.hasNoargCon { + if !jinf.genNoargCon { continue } } @@ -1328,7 +1324,7 @@ func (g *JavaGen) GenC() error { for _, f := range jinf.cons { g.genJNIConstructor(f, sName) } - if jinf.hasNoargCon { + if jinf.genNoargCon { g.Printf("JNIEXPORT jobject JNICALL\n") g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), sName, java.JNIMangle("__New")) g.Indent() diff --git a/bind/testdata/classes.java.c.golden b/bind/testdata/classes.java.c.golden index 6e58879..41942e1 100644 --- a/bind/testdata/classes.java.c.golden +++ b/bind/testdata/classes.java.c.golden @@ -125,6 +125,9 @@ Java_go_java_Java__1init(JNIEnv *env, jclass _unused) { clazz = (*env)->FindClass(env, "go/java/Future"); proxy_class_java_Future = (*env)->NewGlobalRef(env, clazz); proxy_class_java_Future_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); + clazz = (*env)->FindClass(env, "go/java/Object"); + proxy_class_java_Object = (*env)->NewGlobalRef(env, clazz); + proxy_class_java_Object_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); clazz = (*env)->FindClass(env, "go/java/Runnable"); proxy_class_java_Runnable = (*env)->NewGlobalRef(env, clazz); proxy_class_java_Runnable_cons = (*env)->GetMethodID(env, clazz, "", "(Lgo/Seq$Ref;)V"); @@ -207,6 +210,12 @@ Java_go_java_InputStream_getInputStream(JNIEnv *env, jobject this) { return _r0; } +JNIEXPORT jobject JNICALL +Java_go_java_Object__1_1New(JNIEnv *env, jclass clazz) { + int32_t refnum = new_java_Object(); + return go_seq_from_refnum(env, refnum, NULL, NULL); +} + JNIEXPORT void JNICALL Java_go_java_Object_setObject(JNIEnv *env, jobject this, jobject v) { int32_t o = go_seq_to_refnum(env, this); diff --git a/bind/testdata/classes.java.golden b/bind/testdata/classes.java.golden index aaba116..2716ec9 100644 --- a/bind/testdata/classes.java.golden +++ b/bind/testdata/classes.java.golden @@ -75,6 +75,12 @@ public final class Object extends java.lang.Object implements Seq.GoObject { private final Seq.Ref ref; + Object(Seq.Ref ref) { this.ref = ref; } + + public Object() { this.ref = __New(); } + + private static native Seq.Ref __New(); + @Override public final int incRefnum() { int refnum = ref.refnum; Seq.incGoRef(refnum); diff --git a/bind/testpkg/javapkg/classes.go b/bind/testpkg/javapkg/classes.go index 8386596..da18266 100644 --- a/bind/testpkg/javapkg/classes.go +++ b/bind/testpkg/javapkg/classes.go @@ -145,3 +145,7 @@ func NewJavaObject() lang.Object { func NewJavaInteger() lang.Integer { return Integer.New_I(42) } + +type NoargConstructor struct { + util.BitSet // An otherwise unused class with a no-arg constructor +} diff --git a/internal/importers/java/java.go b/internal/importers/java/java.go index efc22fe..233a022 100644 --- a/internal/importers/java/java.go +++ b/internal/importers/java/java.go @@ -46,6 +46,8 @@ type Class struct { Abstract bool Interface bool Throwable bool + // Whether the class has a no-arg constructor + HasNoArgCon bool } // Func is a Java static function or method or constructor. @@ -444,8 +446,12 @@ func (j *importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { if err != nil { return nil, err } - if len(cls.Supers) == 0 && name != "java.lang.Object" { - cls.Supers = append(cls.Supers, "java.lang.Object") + if len(cls.Supers) == 0 { + if name == "java.lang.Object" { + cls.HasNoArgCon = true + } else { + cls.Supers = append(cls.Supers, "java.lang.Object") + } } cls.JNIName = JNIMangle(cls.Name) clsElems := strings.Split(cls.Name, ".") @@ -503,6 +509,7 @@ func (j *importer) scanClass(s *bufio.Scanner, name string) (*Class, error) { f.Final = final f.Constructor = f.Name == cls.FindName if f.Constructor { + cls.HasNoArgCon = cls.HasNoArgCon || len(f.Params) == 0 f.Public = f.Public && !cls.Abstract f.Name = "new" f.Ret = &Type{Class: name, Kind: Object}