java nashorn accessing superclass members - java

Im working with nashorn engine im trying to extend following java class
public abstract class AbstractClass {
protected String name;
protected long id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void init() {
}
Javascript code: In the method init() i want to access superclass members (directly set value of protected fields or use public setters)
var extended = Java.extend(AbstractClass.static , {
init: function() {
extended.name = "name"; //name is null
setName("name") //exception <eval>:6 ReferenceError: "setName" is not defined
}
});
In java i create object instance and call init method, but field "name" is null.
i've also tried to use Java.super(extended ).setName("name"); but this threw an exception <eval>:7 TypeError: Cannot call undefined
How can i access superclass members from javascript and nashorn?

Java.extend creates a subclass and not a subclass instance. But Java.super requires a subclass instance as an argument. So, the following script works:
var extended = new (Java.extend(Java.type("AbstractClass"))) {
init: function() {
Java.super(extended).setName("foo");
}
};
extended.init();
print(extended.name);
Somewhat larger example usage of Java.super is here
https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions#Nashornextensions-java_super

Related

Unable to access methods using dynamic polymorphism [JAVA] [duplicate]

This question already has answers here:
Upcasting/Downcasting in Java
(3 answers)
Closed 3 years ago.
I am trying to solve the following problem
I have made the following hierarchy.
public abstract class Employee{
private String name;
private Integer id;
protected Type type;
Employee(){}
Employee(String name,Integer id){
this.name = name;
this.type = type;
}
abstract public void calculatePay();
protected void benifits(){
System.out.println("Basic Benifts");
}
public void printType(){
System.out.println(this.type);
}
}
public class Intern extends Employee{
Intern(){
super("default",123);
}
Intern(String name,Integer id){
super(name,id);
this.type = Type.Intern;
}
public void calculatePay(){
System.out.println("Intern Pay");
}
}
class Developer extends Employee{
Developer(){
super("default",123);
}
Developer(String name,Integer id){
super(name,id);
this.type = Type.Developer;
}
public void calculatePay(){
System.out.println("Developer Pay");
}
protected void benifits(){
super.benifits();
System.out.println("Developer Benifits");
}
}
class Manager extends Developer{
public Manager(){
super("default",123);
}
public Manager(String name,Integer id){
super(name,id);
this.type = Type.Manager;
}
public void calculatePay(){
System.out.println("Manager Pay");
}
public void benifits(){
super.benifits();
System.out.println("Manger Benifits");
}
public void foo(){
System.out.println("foo");
}
}
And the driver is as follows
class Driver{
public static void main(String args[]){
Employee manager = new Manager("Ali",1);
manager.calculatePay();
manager.benifits();
manager.printType();
manager.foo();
}
}
Type is an Enumeration.
Now the problem is that I can't access foo() method using dynamic approach. But when I do static polymorphism like Manager manager = new Manager() I can access it.
What is the particular reason of this behavior. Is my design correct? What would be a better design? And which design pattern should I use?
There is no need to have the Type enum, the class itself (i.e. Intern) represents the employee type.
Related to the issue of not being able to call manager.foo() is because from a variable of a specific type you can call only those methods which are declared on that type (class).
In your case, when you declare Employee manager = new Manager("Ali", 1); you can call methods which are declared on Employee, in this case foo() is declared on Manager class
When you do Employee manager = new Manager("Ali",1); even though you are creating a Manager instance but the type is Employee, since the type is Employee the compiler do not know manager.foo(); is.
So you have to defile a void foo() method it can be abstract also.

Initialize a class having another class object as member variable

This is my first class:
package trickycorejava;
public class InnerClass {
int id;
oneClass oneClass;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public trickycorejava.oneClass getOneClass() {
return oneClass;
}
public void setOneClass(trickycorejava.oneClass oneClass) {
this.oneClass = oneClass;
}
public InnerClass(int id, trickycorejava.oneClass oneClass) {
this.id = id;
this.oneClass = oneClass;
}
public InnerClass(int id){
this.id = id;
}
}
class oneClass {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
This is the class where the main method exists, observe that the package is different:
package trickycorejava.constructor;
import trickycorejava.InnerClass;
public class InnerClassTest {
public static void main(String[] args) {
InnerClass innerClass = new InnerClass(1);
}
}
How can I initialize the InnerClass with constructor in this case? If I use
InnerClass innerClass = new InnerClass(1, new oneClass("Test"));
I get the error that oneClass is not public cannot be access from outside package.
As Turing85 pointed out the oneClass should be in it's own file, otherwise it's going to be package-private which means you can only access it from classes of the same package.
Is there another way? There is, but it's not going to be a simple constructor call. Using reflection you can bypass class, field and method invocation protection.
public class InnerClassTest {
public static void main(String[] args) throws Exception {
Constructor<OneClass> constructor = OneClass.class.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
OneClass instance = constructor.newInstance("John");
InnerClass innerClass = new InnerClass(1, instance);
}
}
What this does is that it finds the constructor that is private to Main because the class is package-private. Then it disables the protection of it, note that these are temporary, the Constructor object is a new reference and only allows the invocation via this reference.
But I don't recommend doing this extensively. Reflection has some use cases, mainly to aid programmers in frameworks like Spring, but otherwise it can break object oriented patterns.

"No setter/field for field found on class"

I'm creating an app in Android Studio, which connects to a Cloud Firestore database. In the database I have the following structure:
Myclass
- name = "test"
- subclass
- 0 = "String 1"
- 1 = "String 2"
The class itself is declared like this (irrelevant bits removed):
public class Myclass {
private String name;
private String[] subclass;
// CONSTRUCTOR
public Chart() {}
//GETTERS
public String getName() { return this.name; }
// SETTERS
public void setSubclass(String[] thisSubclass) { this.subclass = thisSubclass; }
}
In the activity, the Myclass object is set up like this (again, irrelevant bits removed):
public class MyclassActivity {
DocumentReference docRef;
Myclass myItem;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up database connection, read in itemId etc...
// ...omitted for clarity...
docRef = databaseRef.collection("myclass").document(itemId);
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
myItem = document.toObject(Myclass.class);
}
}
}
}
This reads in the Myclass object, with the name set correctly, but the subclass object doesn't get set up - it's still null.
In the debug console there's the following message:
No setter/field for subclass found on class path.to.app.Myclass
The 'setSubclass' function is greyed out, as if it's never used. I'm sure the problem is something obvious, but I can't see it.
Your problem right now its that your class name must be the same than the constructor. Also you need to add a getter to your subclass parameter.
public class Chart {
private String name;
private String[] subclass;
public Chart() {
//Default empty constructor, required for Firebase.
}
public Chart(String name, String[] subclass) {
this.name = name;
this.subclass = subclass;
}
public String getName() {
return this.name;
}
public String[] getSubclass() {
return subclass;
}
}
In other hand, you don't need to add the setters. They are not required. Firebase will set the value into the field. But you should add them if you're going to interact with the class from outside.
There will be some cases where you want to have different names on your parameters, maybe because you want to follow a camelCase nomenclature or something. If that's the case you can use the annotation #PropertyName to provide a different name in your database and keep your model as you want. For example:
public class Chart {
#PropertyName("name")
private String mName;
#PropertyName("subclass")
private String[] mSubclass;
public Chart() {
}
#PropertyName("name")
public String getmName() {
return mName;
}
#PropertyName("subclass")
public String[] getmSubclass() {
return mSubclass;
}
}
You have two errors in your model class. First one would be the name of the constructor which is different than the name of the class and should be the same. And the second, for the subclass field you have only defined the setter but without a getter.
Your Myclass class should look like this:
public class MyClass {
private String name;
private String[] subclass;
public MyClass() {}
public MyClass(String name, String[] subclass) {
this.name = name;
this.subclass = subclass;
}
public String getName() { return name; }
public String[] getSubclass() { return subclass; }
}
Setters are not not required. If there is no setter for a JSON property, the Firebase client will set the value directly onto the field, that's why is called idiomatic. If you need them explicitly in your code, just add the following setters to your model class like this:
public void setName(String name) { this.name = name; }
public void setSubclass(String[] subclass) { this.subclass = subclass; }
Regarding the use of arrays in the Cloud Firestore database, please see my answer from this post.

How to generify the return type of a method that returns the object its called from [duplicate]

This question already has answers here:
Returning an objects subclass with generics
(4 answers)
Closed 5 years ago.
If this question has already been asked i could not find it.
Here is a simplified example of what i am trying to do.
public static class SuperClass {
private String name;
public <? extends SuperClass> setName(String name)
this.name = name;
return this;
}
}
public static class SubClass extends SuperClass {
private int id;
public void setId(int id) {
this.id = id;
}
}
//Usage
SubClass subclass = new SubClass();
subClass.setName("Some Name").setId(0);
So what i need is for setName to return whatever class its actually called from as oppose to the class its defined in. (In this case it would return an instance of SubClass instead of SuperClass, but if for example SubClass was then extended by SubClass2 it would return an instance of SubClass2)
Is what im asking possible via generics?
You can add a type to the SuperClass declaration and use it in the returned type of the setName() method.
It will force all inherited subclass to return the type declared in their extending declaration to SuperClass.
But to achieve it you should cast this to T in setName().
public class SuperClass<T extends SuperClass<T>> {
private String name;
public T setName(String name) {
this.name = name;
return (T) this;
}
}
And declare subclass in this way :
public class SubClass extends SuperClass<SubClass> {
...
public void setId(int i) {
...
}
...
}
And now you could do :
SubClass subclass = new SubClass();
subclass.setName("Some Name").setId(0);
Another way to address the problem :
Using covariant return types in the overrided methods will allow you to specify subclass in the returned type. You can use it instead of generics.
The single thing to notice : you will have to be careful to define explicitly the return type by overriding the method in each subclass.
Without generics, nothing will force you to do it (but an unit test).
public class SuperClass {
private String name;
public SuperClass setName(String name) {
this.name = name;
return this;
}
}
public class SubClass extends SuperClass {
#Override
public SubClass setName(String name) {
super.setName(name);
return this;
}
public void setId(int i) {
...
}
}

Java overriding method Error

basically I created a Person class and a constructor which sets the name,last name,age of the Person.all the properties of the class were set the private as it should be. I have made setters and getters for all the properties. On the main method I tried to override one of the setters just for practice reason. Its did draw an error saying Person.name not visible which means it cannot access private, Why this is happening, I mean if wasn't overriding the method it would have access. but if I set it to protected mode i will work.
Here is the code:
class Person {
private int age;
private String name;
private String last_name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public Person(int age, String name, String last_name) {
this.age = age;
this.name = name;
this.last_name = last_name;
}
}
public class main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person per = new Person(15,"bb","Sb") {
public void setName(String name) {
this.name = "aaaa";
}
};
per.setName("asdfaf");
System.out.println(per.getName());
}
}
A private member is only accessible in the class in which it is declared.
You created an anonymous sub-class of Person and tried to access a private member of the super-class from the sub-class. This is never allowed.
When developers of a class wish to allow access to certain members of the class to its sub-classes, they set the acess level to protected.
You have created a class named Person and in the following lines you are trying to create an anonymous subclass:
Person per = new Person(15,"bb","Sb") {
public void setName(String name) {
this.name = "aaaa";
}
};
As mentioned in doc:
A subclass does not inherit the private members of its parent class
Here your anonymous subclass is trying to access private field name directly and so is the error. You can use getter/setter which are public. You can also check this related question on SO.
You cannot access private fields from outside your class, even if you are overriding it. You are basically defining a new subclass of Person in your main(), which isn't allowed access to the private field Person.name. However, it can access a protected field.
Basic idea behind overriding is to redefine existing functionality and give new definition to it. If you refer to documentation, private member variables are only accessible in it own class. That why it is not available in your anonymous sub-class implementation.
Note: Generally we do not override setter methods as they are not a functionality.
This is called encapsulation . You can not access private vars from other classes . you can find more description here

Categories