2
0
mirror of synced 2025-02-23 14:58:12 +00:00

bind: generate Java constructors for every exported struct

A recent CL added Java constructors to generated classes that extends
or implements other Java classes and interfaces. Constructors for a
struct S are Go functions on the form

func NewS...(...) *S

If no such constructors exists, a default empty constructor is
generated.

Expand that to cover every exported Go struct.

Fixes golang/go#17086

Change-Id: I910aba13d5884c3f67c946c62a8ac4a3db8e2ea7
Reviewed-on: https://go-review.googlesource.com/29710
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Elias Naur 2016-09-23 12:31:57 +02:00
parent 89b8360218
commit 3f7b83ffd4
13 changed files with 123 additions and 38 deletions

View File

@ -26,6 +26,10 @@ type JavaGen struct {
jstructs map[*types.TypeName]*javaClassInfo jstructs map[*types.TypeName]*javaClassInfo
clsMap map[string]*java.Class clsMap map[string]*java.Class
// Constructors is a map from Go struct types to a list
// of exported constructor functions for the type, on the form
// func New<Type>(...) *Type
constructors map[*types.TypeName][]*types.Func
} }
type javaClassInfo struct { type javaClassInfo struct {
@ -36,9 +40,6 @@ type javaClassInfo struct {
methods map[string]*java.Func methods map[string]*java.Func
// Does the class need a default no-arg constructor // Does the class need a default no-arg constructor
genNoargCon bool genNoargCon bool
// Constructors for the type, on the form
// func New<Type>(...) *Type
cons []*types.Func
} }
// Init intializes the embedded Generator and initializes the Java class information // Init intializes the embedded Generator and initializes the Java class information
@ -50,6 +51,7 @@ func (g *JavaGen) Init(classes []*java.Class) {
g.clsMap[cls.Name] = cls g.clsMap[cls.Name] = cls
} }
g.jstructs = make(map[*types.TypeName]*javaClassInfo) g.jstructs = make(map[*types.TypeName]*javaClassInfo)
g.constructors = make(map[*types.TypeName][]*types.Func)
for _, s := range g.structs { for _, s := range g.structs {
classes := embeddedJavaClasses(s.t) classes := embeddedJavaClasses(s.t)
if len(classes) == 0 { if len(classes) == 0 {
@ -87,8 +89,8 @@ func (g *JavaGen) Init(classes []*java.Class) {
if jinf != nil { if jinf != nil {
sig := f.Type().(*types.Signature) sig := f.Type().(*types.Signature)
jinf.genNoargCon = jinf.genNoargCon && sig.Params().Len() > 0 jinf.genNoargCon = jinf.genNoargCon && sig.Params().Len() > 0
jinf.cons = append(jinf.cons, f)
} }
g.constructors[t] = append(g.constructors[t], f)
} }
} }
} }
@ -178,23 +180,22 @@ func (g *JavaGen) genStruct(s structInfo) {
g.Printf("static { %s.touch(); }\n\n", g.className()) g.Printf("static { %s.touch(); }\n\n", g.className())
g.genProxyImpl(n) g.genProxyImpl(n)
if jinf != nil { cons := g.constructors[s.obj]
for _, f := range jinf.cons { for _, f := range cons {
if !g.isSigSupported(f.Type()) { if !g.isSigSupported(f.Type()) {
g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", n, f.Name()) g.Printf("// skipped constructor %s.%s with unsupported parameter or return types\n\n", n, f.Name())
continue continue
}
g.genConstructor(f, n)
} }
if jinf.genNoargCon { g.genConstructor(f, n, jinf != nil)
// Generate constructor for Go instantiated instances. }
g.Printf("%s(Seq.Ref ref) { this.ref = ref; }\n\n", n) if jinf == nil || jinf.genNoargCon {
// constructor for Go instantiated instances.
g.Printf("%s(Seq.Ref ref) { this.ref = ref; }\n\n", n)
if len(cons) == 0 {
// Generate default no-arg constructor // Generate default no-arg constructor
g.Printf("public %s() { this.ref = __New(); }\n\n", n) g.Printf("public %s() { this.ref = __New(); }\n\n", n)
g.Printf("private static native Seq.Ref __New();\n\n") g.Printf("private static native Seq.Ref __New();\n\n")
} }
} else {
g.Printf("%s(Seq.Ref ref) { this.ref = ref; }\n\n", n)
} }
for _, f := range fields { for _, f := range fields {
@ -266,22 +267,25 @@ func (g *JavaGen) genStruct(s structInfo) {
g.Printf("}\n\n") g.Printf("}\n\n")
} }
func (g *JavaGen) genConstructor(f *types.Func, n string) { func (g *JavaGen) genConstructor(f *types.Func, n string, jcls bool) {
g.Printf("public %s(", n) g.Printf("public %s(", n)
g.genFuncArgs(f, nil) g.genFuncArgs(f, nil)
g.Printf(") {\n") g.Printf(") {\n")
g.Indent() g.Indent()
g.Printf("super(")
sig := f.Type().(*types.Signature) sig := f.Type().(*types.Signature)
params := sig.Params() params := sig.Params()
for i := 0; i < params.Len(); i++ { if jcls {
if i > 0 { g.Printf("super(")
g.Printf(", ") for i := 0; i < params.Len(); i++ {
if i > 0 {
g.Printf(", ")
}
g.Printf(paramName(params, i))
} }
g.Printf(paramName(params, i)) g.Printf(");\n")
} }
g.Printf(");\n") g.Printf("this.ref = ")
g.Printf("this.ref = __%s(", f.Name()) g.Printf("__%s(", f.Name())
for i := 0; i < params.Len(); i++ { for i := 0; i < params.Len(); i++ {
if i > 0 { if i > 0 {
g.Printf(", ") g.Printf(", ")
@ -1330,21 +1334,20 @@ func (g *JavaGen) GenC() error {
} }
for _, s := range g.structs { for _, s := range g.structs {
sName := s.obj.Name() sName := s.obj.Name()
cons := g.constructors[s.obj]
jinf := g.jstructs[s.obj] jinf := g.jstructs[s.obj]
if jinf != nil { for _, f := range cons {
for _, f := range jinf.cons { g.genJNIConstructor(f, sName)
g.genJNIConstructor(f, sName) }
} if len(cons) == 0 && (jinf == nil || jinf.genNoargCon) {
if jinf.genNoargCon { g.Printf("JNIEXPORT jobject JNICALL\n")
g.Printf("JNIEXPORT jobject JNICALL\n") g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), sName, java.JNIMangle("__New"))
g.Printf("Java_%s_%s_%s(JNIEnv *env, jclass clazz) {\n", g.jniPkgName(), sName, java.JNIMangle("__New")) g.Indent()
g.Indent() g.Printf("int32_t refnum = new_%s_%s();\n", g.pkgPrefix, sName)
g.Printf("int32_t refnum = new_%s_%s();\n", g.pkgPrefix, sName) // Pass no proxy class so that the Seq.Ref is returned instead.
// Pass no proxy class so that the Seq.Ref is returned instead. g.Printf("return go_seq_from_refnum(env, refnum, NULL, NULL);\n")
g.Printf("return go_seq_from_refnum(env, refnum, NULL, NULL);\n") g.Outdent()
g.Outdent() g.Printf("}\n\n")
g.Printf("}\n\n")
}
} }
for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) { for _, m := range exportedMethodSet(types.NewPointer(s.obj.Type())) {

View File

@ -527,6 +527,17 @@ public class SeqTest extends InstrumentationTestCase {
assertTrue("Go struct passed through Java should not be wrapped", Testpkg.callCDupper(cdup)); assertTrue("Go struct passed through Java should not be wrapped", Testpkg.callCDupper(cdup));
} }
public void testConstructor() {
Interface i = new Concrete();
i.f();
S2 s = new S2(1, 2);
assertEquals("new S2().sum", 3.0, s.sum());
assertEquals("new S2().tryTwoStrings", "gostring", s.tryTwoStrings("go", "string"));
new S3();
S4 s4 = new S4(123);
assertEquals("Constructor argument", 123, s4.getI());
}
public void testEmptyError() { public void testEmptyError() {
try { try {
Testpkg.emptyError(); Testpkg.emptyError();

View File

@ -39,6 +39,12 @@ Java_go_ignore_Ignore__1init(JNIEnv *env, jclass _unused) {
// skipped function Result with unsupported parameter or return types // skipped function Result with unsupported parameter or return types
JNIEXPORT jobject JNICALL
Java_go_ignore_S__1_1New(JNIEnv *env, jclass clazz) {
int32_t refnum = new_ignore_S();
return go_seq_from_refnum(env, refnum, NULL, NULL);
}
// skipped function S.Argument with unsupported parameter or return types // skipped function S.Argument with unsupported parameter or return types
// skipped function S.Result with unsupported parameter or return types // skipped function S.Result with unsupported parameter or return types

View File

@ -19,6 +19,10 @@ public final class S implements Seq.Proxy, I {
S(Seq.Ref ref) { this.ref = ref; } S(Seq.Ref ref) { this.ref = ref; }
public S() { this.ref = __New(); }
private static native Seq.Ref __New();
// skipped field S.F with unsupported type: *types.Interface // skipped field S.F with unsupported type: *types.Interface
// skipped method S.Argument with unsupported parameter or return types // skipped method S.Argument with unsupported parameter or return types

View File

@ -31,6 +31,12 @@ Java_go_issue10788_Issue10788__1init(JNIEnv *env, jclass _unused) {
} }
JNIEXPORT jobject JNICALL
Java_go_issue10788_TestStruct__1_1New(JNIEnv *env, jclass clazz) {
int32_t refnum = new_issue10788_TestStruct();
return go_seq_from_refnum(env, refnum, NULL, NULL);
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_go_issue10788_TestStruct_setValue(JNIEnv *env, jobject this, jstring v) { Java_go_issue10788_TestStruct_setValue(JNIEnv *env, jobject this, jstring v) {
int32_t o = go_seq_to_refnum(env, this); int32_t o = go_seq_to_refnum(env, this);

View File

@ -19,6 +19,10 @@ public final class TestStruct implements Seq.Proxy {
TestStruct(Seq.Ref ref) { this.ref = ref; } TestStruct(Seq.Ref ref) { this.ref = ref; }
public TestStruct() { this.ref = __New(); }
private static native Seq.Ref __New();
public final native String getValue(); public final native String getValue();
public final native void setValue(String v); public final native void setValue(String v);

View File

@ -20,6 +20,12 @@ Java_go_issue12328_Issue12328__1init(JNIEnv *env, jclass _unused) {
proxy_class_issue12328_T_cons = (*env)->GetMethodID(env, clazz, "<init>", "(Lgo/Seq$Ref;)V"); proxy_class_issue12328_T_cons = (*env)->GetMethodID(env, clazz, "<init>", "(Lgo/Seq$Ref;)V");
} }
JNIEXPORT jobject JNICALL
Java_go_issue12328_T__1_1New(JNIEnv *env, jclass clazz) {
int32_t refnum = new_issue12328_T();
return go_seq_from_refnum(env, refnum, NULL, NULL);
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_go_issue12328_T_setErr(JNIEnv *env, jobject this, jobject v) { Java_go_issue12328_T_setErr(JNIEnv *env, jobject this, jobject v) {
int32_t o = go_seq_to_refnum(env, this); int32_t o = go_seq_to_refnum(env, this);

View File

@ -19,6 +19,10 @@ public final class T implements Seq.Proxy {
T(Seq.Ref ref) { this.ref = ref; } T(Seq.Ref ref) { this.ref = ref; }
public T() { this.ref = __New(); }
private static native Seq.Ref __New();
public final native java.lang.Exception getErr(); public final native java.lang.Exception getErr();
public final native void setErr(java.lang.Exception v); public final native void setErr(java.lang.Exception v);

View File

@ -52,6 +52,12 @@ Java_go_structs_Structs_identityWithError(JNIEnv* env, jclass _clazz, jobject s)
return _r0; return _r0;
} }
JNIEXPORT jobject JNICALL
Java_go_structs_S__1_1New(JNIEnv *env, jclass clazz) {
int32_t refnum = new_structs_S();
return go_seq_from_refnum(env, refnum, NULL, NULL);
}
JNIEXPORT jobject JNICALL JNIEXPORT jobject JNICALL
Java_go_structs_S_identity(JNIEnv* env, jobject __this__) { Java_go_structs_S_identity(JNIEnv* env, jobject __this__) {
int32_t o = go_seq_to_refnum(env, __this__); int32_t o = go_seq_to_refnum(env, __this__);
@ -100,6 +106,12 @@ Java_go_structs_S_getY(JNIEnv *env, jobject this) {
return _r0; return _r0;
} }
JNIEXPORT jobject JNICALL
Java_go_structs_S2__1_1New(JNIEnv *env, jclass clazz) {
int32_t refnum = new_structs_S2();
return go_seq_from_refnum(env, refnum, NULL, NULL);
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_go_structs_S2_m(JNIEnv* env, jobject __this__) { Java_go_structs_S2_m(JNIEnv* env, jobject __this__) {
int32_t o = go_seq_to_refnum(env, __this__); int32_t o = go_seq_to_refnum(env, __this__);

View File

@ -19,6 +19,10 @@ public final class S implements Seq.Proxy {
S(Seq.Ref ref) { this.ref = ref; } S(Seq.Ref ref) { this.ref = ref; }
public S() { this.ref = __New(); }
private static native Seq.Ref __New();
public final native double getX(); public final native double getX();
public final native void setX(double v); public final native void setX(double v);
@ -79,6 +83,10 @@ public final class S2 implements Seq.Proxy, I {
S2(Seq.Ref ref) { this.ref = ref; } S2(Seq.Ref ref) { this.ref = ref; }
public S2() { this.ref = __New(); }
private static native Seq.Ref __New();
public native void m(); public native void m();
public native String string(); public native String string();
@Override public boolean equals(Object o) { @Override public boolean equals(Object o) {

View File

@ -27,6 +27,12 @@ Java_go_vars_Vars__1init(JNIEnv *env, jclass _unused) {
} }
JNIEXPORT jobject JNICALL
Java_go_vars_S__1_1New(JNIEnv *env, jclass clazz) {
int32_t refnum = new_vars_S();
return go_seq_from_refnum(env, refnum, NULL, NULL);
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_go_vars_Vars_setABool(JNIEnv *env, jclass clazz, jboolean v) { Java_go_vars_Vars_setABool(JNIEnv *env, jclass clazz, jboolean v) {
char _v = (char)v; char _v = (char)v;

View File

@ -19,6 +19,10 @@ public final class S implements Seq.Proxy, I {
S(Seq.Ref ref) { this.ref = ref; } S(Seq.Ref ref) { this.ref = ref; }
public S() { this.ref = __New(); }
private static native Seq.Ref __New();
@Override public boolean equals(Object o) { @Override public boolean equals(Object o) {
if (o == null || !(o instanceof S)) { if (o == null || !(o instanceof S)) {
return false; return false;

View File

@ -547,3 +547,14 @@ var GlobalErr error = errors.New("global err")
func IsGlobalErr(err error) bool { func IsGlobalErr(err error) bool {
return GlobalErr == err return GlobalErr == err
} }
type S3 struct {
}
type S4 struct {
I int
}
func NewS4WithInt(i int) *S4 {
return &S4{i}
}