How to extends new class ?
Closed this issue · 6 comments
Now ,I have a class extends from JSObject,
`interface MzObjectClass {
public void _MzObjectClass(Integer x, String y) throws JSException;
public void func1(Integer a);
public void func2(Integer b, Integer c) throws JSException;
}
public class MzObject extends JSObject implements MzObjectClass {
public MzObject(JSContext ctx) throws JSException {
super(ctx, MzObjectClass.class, MzObject.class); // This constructor!;
System.out.println("MzObject init1");
}
public MzObject(long objRef, JSContext ctx){
super(objRef, ctx);
System.out.println("MzObject init2");
}
@Override
public void _MzObjectClass(Integer x, String y) throws JSException{
property("x", x);
property("y", y);
System.out.println("MzObject init3");
}
@Override
public void func1(Integer a) {
System.out.println(a);
}
@Override
public void func2(Integer b, Integer c) throws JSException{
Integer out = b + c + property("x").toNumber().intValue();
System.out.println(out);
}
}`
If I want create a new class extends from MzObjetc,HOW?
Hmm. I see what you are asking. When you try to instantiate a new
class that extends MzObject
, it will create the MzObject
, not your subclass. If you change your constructor to use getClass()
instead of MzObject.class
it should do what you want, no? getClass()
returns the runtime class of the object which would be your subclass.
public MzObject(JSContext ctx) throws JSException {
super(ctx, MzObjectClass.class, getClass()); // This constructor!;
System.out.println("MzObject init1");
}
Was that the question?
Please re-open if this doesn't solve your problem.
Hi Mr. Lange.
Thanks a lot for the awesome library.
But, are you sure the super(ctx, TheClass.class, getClass())
is the solution?
Because I found some issues on that:
- You've already deprecated this constructor.
- You certainly know that the
getClass()
method in this example is called before thesuper
; and because of that, java gives a compile error. As the super method should be called before any other methods in constructor.
I'm thinking of some solutions such as using java reflection directly in parent constructor or things like that. But tried first to ask you if any implemented solutions already exist. Otherwise I'll use my own modifications.
Again thanks for the great job.
You are correct that this would not work. However, this question is part of a deprecated constructor in 3.0+. This has been simplified greatly and you shouldn't need to do this in any case. What are you trying to accomplish exactly? I can probably guide you.
What I wana do is:
public class TestClass extends JSObject {
public int a = 12;
public TestClass(JSContext jsContext){
super(jsContext, TestClass.class);
JSObjectPropertiesMap<Object> map = new JSObjectPropertiesMap<>(this, Object.class);
map.put("a",a);
}
public int f(){
return a * 2;
}
}
and then:
public class TestClass2 extends TestClass {
public int b = 8;
public TestClass2(JSContext jsContext){
super(jsContext);
JSObjectPropertiesMap<Object> map = new JSObjectPropertiesMap<>(this, Object.class);
map.put("b", b);
}
public int f2(){
return b * b;
}
}
and finally:
jsContext.property("t", new TestClass2(jsContext));
tv.setText("t.f2() : " + jsContext.property("t").toObject().property("f2").toFunction().call());
I know that a simple way of doing this is to pass .class
reference in the parent constructor. like this:
...
//TestClass constructor
public TestClass(JSContext ctx, Class<?> iface){
//
}
...
But it's not a good practice for inheritance, as all subclasses have to give themselves in their constructors. Instead, I recommend to do this modification in the top parent JSObject
constructor:
public JSObject(JSContext ctx /*, final Class<?> iface*/) {
context = ctx;
context.sync(new Runnable() {
@Override
public void run() {
valueRef = make(context.ctxRef(), 0L);
// Method[] methods = iface.getDeclaredMethods(); ==> instead of this line
// use this:
Class c = getClass();
Method[] methods = new Method[0];
while(!c.getName().equals("JSObject")){
// Merge arrays in your way...
merge(methods, c.getDeclaredMethods);
// Note that merge method we implement, won't add two methods with the same name to the result. ==> so just the child method stays in the merged array.
c = c.getSuperClass();
}
for (Method m : methods) {
JSObject f = new JSFunction(context, m,
JSObject.class, JSObject.this);
property(m.getName(), f);
}
}
});
context.persistObject(this);
}
and even fields can be manipulated through java reflection as well.
So here's what you can do to solve that problem:
public class TestClass extends JSObject {
public int a = 12;
public TestClass(JSContext jsContext){
super(jsContext);
JSObjectPropertiesMap<Object> map = new JSObjectPropertiesMap<>(this, Object.class);
map.put("a",a);
map.put("f",new JSFunction(jsContext, "f", JSObject.class, this);
}
public int f(){
return a * 2;
}
}
Note the JSFunction
constructor. The fourth parameter is the object on which you want the method called. Incidentally, this is all that constructor you are trying to use does in the end.