1

I am attempting extend a Java class through JavaScript Nashorn and then call method from the super class. Normally this wouldn't be an issue, though I'm overriding a method, that's being called by the super class' constructor.

Below is my code:

const MyClass = Java.type("com.example.MyClass")

const myInstance = new (Java.extend(MyClass, {
    myMethod: () => {
        const _super = Java.super(myInstance)

        _super.doWhatever()
    }
}))()

I set the variable myInstance to a new instance of the extended class, which again is being referenced from within the method myMethod, which is being called by the constructor, which causes myInstance to be undefined by the time myMethod is called.

I'm having trouble figuring out a way to fix this issue, without having to extend it through Java, which would cause issues in the environment I work in.

EDIT:
I have no way of changing the Java code within MyClass

Tarkan
  • 541
  • 1
  • 4
  • 27
  • The fault, I'd say, is with the superclass. See [What's wrong with overridable method calls in constructors?](http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors) – Jorn Vernee Feb 28 '17 at 23:54
  • The problem is that I don't have access to edit the Java itself. The scripts are you used to extend an already built piece of software that I can in no way change. – Tarkan Mar 01 '17 at 04:23
  • You could send whoever is providing you with `MyClass` an email, asking them to fix this problem. Or, If they are on github for instance, you could post an 'issue' there. The only other solution is to not use `myInstance` (i.e. `this`), since it will be un-initialized when `myMethod` is called. – Jorn Vernee Mar 01 '17 at 08:35
  • Something else I guess you could try, is assign `myMethod` after the creation of `myInstance`. But then it wouldn't be called by the super constructor. – Jorn Vernee Mar 01 '17 at 08:44
  • Yeah, that's an issue :/. Not quite sure what to do, other than having to extend the class in Java and then call it from the JavaScript afterwards. – Tarkan Mar 01 '17 at 18:45

1 Answers1

0

"myInstance" is initialized only after JS "new" operation is completed. This JS "new" involves "new object creation" and "Java constructor call" together (from a single invokedynamic).

You mentioned you're calling myMethod from your (super class) constructor. In this case, you're effectively calling script implemented myMethod method override from super class constructor. But script constant myInstance is not yet initialized. So you'll get error when you attempt Java.super on myInstance which is still undefined!

Root of the problem:

It is not a good idea to call overridable Java methods from a constructor. I recommend you to restructure your java code to avoid calling an overridable method from constructor.

A. Sundararajan
  • 4,277
  • 1
  • 15
  • 30
  • I am aware of this, the root of the problem is however, that I'm extending an already built piece of software and I have no way of changing the structure of the Java code. Which is the reason why I'm trying trying to find a solution, even if it's considered hacky. – Tarkan Mar 01 '17 at 04:27
  • 1
    I'm afraid you don't have even a "hacky" solution for this :( As I mentioned, "new" in JS is one invokedynamic call. Only at the end of call (right hand side expression) the constant in left would be initialized. And constructor calls that overridable method before that variable is initialized. – A. Sundararajan Mar 01 '17 at 15:40
  • I was just thinking if there was an alternative, that didn't require setting the variable `myInstance` to get the instance from within the method. I'm guessing JavaScript has no way of knowing what class instance a method belongs to? – Tarkan Mar 01 '17 at 18:52