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:
parent
89b8360218
commit
3f7b83ffd4
@ -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())) {
|
||||||
|
@ -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();
|
||||||
|
6
bind/testdata/ignore.java.c.golden
vendored
6
bind/testdata/ignore.java.c.golden
vendored
@ -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
|
||||||
|
4
bind/testdata/ignore.java.golden
vendored
4
bind/testdata/ignore.java.golden
vendored
@ -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
|
||||||
|
6
bind/testdata/issue10788.java.c.golden
vendored
6
bind/testdata/issue10788.java.c.golden
vendored
@ -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);
|
||||||
|
4
bind/testdata/issue10788.java.golden
vendored
4
bind/testdata/issue10788.java.golden
vendored
@ -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);
|
||||||
|
|
||||||
|
6
bind/testdata/issue12328.java.c.golden
vendored
6
bind/testdata/issue12328.java.c.golden
vendored
@ -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);
|
||||||
|
4
bind/testdata/issue12328.java.golden
vendored
4
bind/testdata/issue12328.java.golden
vendored
@ -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);
|
||||||
|
|
||||||
|
12
bind/testdata/structs.java.c.golden
vendored
12
bind/testdata/structs.java.c.golden
vendored
@ -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__);
|
||||||
|
8
bind/testdata/structs.java.golden
vendored
8
bind/testdata/structs.java.golden
vendored
@ -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) {
|
||||||
|
6
bind/testdata/vars.java.c.golden
vendored
6
bind/testdata/vars.java.c.golden
vendored
@ -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;
|
||||||
|
4
bind/testdata/vars.java.golden
vendored
4
bind/testdata/vars.java.golden
vendored
@ -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;
|
||||||
|
@ -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}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user