I have One Inner Class and One Outer Class. Using Java Reflection I want to access the data of the inner class instance.
public class OuterClass {
public OuterClass() {
super();
}
public OuterClass(InnerClass innerClass1, InnerClass innerClass2) {
super();
this.innerClass1 = innerClass1;
this.innerClass2 = innerClass2;
}
private InnerClass innerClass1;
private InnerClass innerClass2;
public class InnerClass {
public InnerClass() {
super();
}
public InnerClass(int id, String name, String rollNo) {
super();
this.id = id;
this.name = name;
this.rollNo = rollNo;
}
private int id;
private String name;
private String rollNo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRollNo() {
return rollNo;
}
public void setRollNo(String rollNo) {
this.rollNo = rollNo;
}
}
public InnerClass getInnerClass1() {
return innerClass1;
}
public void setInnerClass1(InnerClass innerClass1) {
this.innerClass1 = innerClass1;
}
public InnerClass getInnerClass2() {
return innerClass2;
}
public void setInnerClass2(InnerClass innerClass2) {
this.innerClass2 = innerClass2;
}
}
Main Class:-
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflection {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass1 = outerClass.new InnerClass(1, "Iftekhar", "1234");
OuterClass.InnerClass innerClass2 = outerClass.new InnerClass(2, "Ahmed", "123");
outerClass.setInnerClass1(innerClass1);
outerClass.setInnerClass2(innerClass2);
Field[] fields = outerClass.getClass().getDeclaredFields();
for (Field f : fields) {
Method method = OuterClass.InnerClass.class.getMethod("getId", null);
int id = (int) method.invoke(f, null);
System.out.println(id);
}
}
}
I am anticipating the output to be 1 and 2. But i am getting the below Exception:-
Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
I am instantiating the inner Class attributes using the way show above.Can anyone please help where i am doing wrong.
You are calling getId() on a java.lang.reflect.Field instance. And a java.lang.reflect.Field is not an instance of OuterClass.InnerClass.
To fix this, you first have to get the value of the field and call getId() on that:
Field[] fields = outerClass.getClass().getDeclaredFields();
// We only have to find the method once and can reuse it
Method method = OuterClass.InnerClass.class.getMethod("getId");
// We have to call .setAccessible because the fields are private
AccessibleObject.setAccessible(fields, true);
for (Field f : fields) {
OuterClass.InnerClass value = (OuterClass.InnerClass) f.get(outerClass);
// At this point, you could also use value.getId();
int id = (int) method.invoke(value);
System.out.println(id);
}
Related
I want to make my Builder pattern as Thread safe But facing issues in that, below is my code:
// Server Side Code
final class Student {
// final instance fields
private final int id;
private final String name;
private final String address;
public Student(Builder builder)
{
this.id = builder.id;
this.name = builder.name;
this.address = builder.address;
}
// Static class Builder
public static class Builder {
/// instance fields
private int id;
private String name;
private String address;
public static Builder newInstance()
{
return new Builder();
}
private Builder() {}
// Setter methods
public Builder setId(int id)
{
this.id = id;
return this;
}
public Builder setName(String name)
{
this.name = name;
return this;
}
public Builder setAddress(String address)
{
this.address = address;
return this;
}
// build method to deal with outer class
// to return outer instance
public Student build()
{
return new Student(this);
}
}
#Override
public String toString()
{
return "id = " + this.id + ", name = " + this.name +
", address = " + this.address;
}
}
----------
There is another class named StudentReceiver.java in which I am using multithreading:
class StudentReceiver {
// volatile student instance to ensure visibility
// of shared reference to immutable objects
private volatile Student student;
public StudentReceiver() throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
public void run() {
student = Student.Builder.newInstance().setId(1).setName("Ram").setAddress("Noida").build();
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
student = Student.Builder.newInstance().setId(2).setName("Shyam").setAddress("Delhi").build();
}
});
t1.start();
t2.start();
//t1.join();
//t2.join();
}
public Student getStudent() {
return student;
}
}
----------
Main class is below from where I am calling these methods:
//Driver class
public class BuilderDemo {
public static void main(String args[]) throws InterruptedException
{
for(int i=0; i<10;i++)
{
StudentReceiver sr = new StudentReceiver();
System.out.println(sr.getStudent());
}
}
}
----------
The output I am getting is like below:
null
null
null
null
null
null
null
null
id = 1, name = Ram, address = Noida
null
Why I am getting null here??
May anyone explain and How to make Builder Pattern thread safe so that it can be used in multithreaaded environment.
Your Builder Pattern is not the problem here. The Constructor of StudentReceiver is.
Starting a Thread inside it without joing it there will lead to the object being assigned, possibly and probably before the Thread even started. So the student Field will not be set for quite some time. So much time in fact, that executing the System.out.println(sr.getStudent()); line right after the constructor will (very probably) receive null from getStundent().
The fix would be to either:
Not use a separate Thread in the Constructor.
Or join the thread inside the Constructor ( which somewhat defeates the Thread's purpose ).
And the Builder class should not be static.
Here is an example of what I'd do:
public interface IBuilder
{
IBuilder setId( int id );
// ...
Student build();
}
final class Student {
// final instance fields
private final int id;
// + other fields - left out for brevity
private Student(Builder builder)
{
this.id = builder.id;
// + other fields
}
private static Object builderLock = new Object();
public static IBuilder getBuilder()
{
synchronized(builderLock)
{
return new Builder();
}
}
// Static class Builder
public class Builder implements IBuilder {
// instance fields
private int id = -1;
// ...
private Builder() {}
// Setter methods
public IBuilder setId(int id) {
this.id = id;
return this;
}
public Student build() {
return new Student(this);
}
}
}
Disclaimer: untested!
I have a class A with setters and getters.
I have a class B where I call a constructor from A and set some variables.
I have a class C where I want to call variables set up in class B.
How can i call that in class C?
public class A{
private String name;
private String status;
private int id;
public A(String status, String name) {
this.status = status;
this.name = name;
}
public String getStatus() {
return status;
}
public String getName() {
return name;
}
public void setStatus(String status) {
this.status = status;
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}}
public class B{
A a;
public void add() {
a= new A("Test", "Test");
}
public void add_to() {
int id = Math.abs(new Random().nextInt());
a.setId(id);
}
public class C{
public void add() {
//How can I call variable id declared in class B???
}
}
Instead of just adding more methods in the class B I would like to continue to use the same constructor with stored variables that I have created in class B already.
I need to code a programm and have some issues doing so:
Super-Class:
public class Kunde {
private String name;
private String adresse;
private double marge;
private int nummer;
public Kunde(String name, String adresse, int nummer) {
this.name = name;
this.adresse = adresse;
this.nummer= nummer;
marge = 2;
}
public void print() {
System.out.println("\nKunde: "+name);
System.out.println("Adresse: "+adresse);
System.out.println("Kundennummer: "+nummer);
System.out.println("Marge: "+marge);
}
public double getMarge() {
return marge;
}
public void setMarge(double marge) {
this.marge = marge;
}
public int getNummer() {
return nummer;
}
}
Main-Class:
public class Main {
public static void main(String[] args) {
Kunde k1 = new Geschaeftskunde("ABC AG", "Weg 3", 100,"CHE.123");
Kunde k2 = new Privatkunde("Hans Müller","Nebenstrasse 2", 101);
k1.print();
k2.print();
}
For the Kunde k1 an error occurs: "The constructor Geschaeftskunde is undefined"
But i actually initialized the constructor as followed:
public class Geschaeftskunde extends Kunde {
private String uid;
public Geschaeftskunde (String name, String adresse, int nummer) {
super(name,adresse,nummer);
}
public String getUid() {
return uid;
}
public void print() {
System.out.println("UID: "+uid);
}
}
In the same way I initialized the constructor for Kunde k2:
public class Privatkunde extends Kunde {
public Privatkunde (String name, String adresse, int nummer) {
super(name,adresse,nummer);
}
}
And for this class this error surprisingly doesnt occur?
Question:
How can i use and change the attribute marge in the classes Geschaeftskunde und Privatkunde when its set on private?
I know that you can use public methodes with that attribute so is the code: "super.setMarge(x);" the right attempt in solving this problem?
The compiler error is due to Geschaeftskunde taking 3 arguments while you call it with 4.
Regarding marge you need to use setMarge(x) and getMarge(). The super is not necessary since Geschaeftskunde/Privatkunde inherit the public methods.
Fixed constructor for Geschaeftskunde:
public Geschaeftskunde (String name, String adresse, int nummer, String uid){
super(name,adresse,nummer);
this.uid = uid;
this.setMarge(2);
}
Privatkundewould be similar.
public class OuterClass implements Serializable {
int id;
ArrayList<InnerClass> listofInner;
public int getId() {
return id;
}
public void setId(int num) {
this.id = num;
}
public ArrayList<InnerClass> getListofInner() {
return listofInner;
}
public void setListofInner(ArrayList<InnerClass> list) {
this.listofInner = list;
}
public static class InnerClass implements Serializable {
String streetno;
private List<InnerClass> children = new ArrayList<InnerClass>();
public void setStreetno(String streetno) {
this.streetno = streetno;
}
public String getStreetno() {
return streetno;
}
public List<InnerClass> getChildren() {
return children;
}
public void setChildren(List<InnerClass> children) {
this.children = children;
}
}
}
OuterClass us = new OuterClass();
us.setId(111);
//Inner
OuterClass.InnerClass ic = new OuterClass.InnerClass();
ic.setStreetno("My Street");
ic.getChildren().add(new OuterClass.InnerClass());
ArrayList<OuterClass.InnerClass> ar = new ArrayList<OuterClass.InnerClass>();
ar.add(ic);
us.setListofInner(ar);
//DF
Encoder<OuterClass> outerClassEncoder = Encoders.bean(OuterClass.class);
Dataset<OuterClass> ds = spark.createDataset(Collections.singletonList(us), outerClassEncoder);
In the above InnerClass class has property
List children = new ArrayList(); this is a type ofInnerClass list. Because of this when I am trying to covert this Custom Object to Dataset. I am getting error
java.lang.StackOverflowError: null
at sun.reflect.generics.reflectiveObjects.TypeVariableImpl.equals(TypeVariableImpl.java:189).
If I remove the children property from InnerClass. It works fine.
So Any one please help me..:)
I've an object pObject
Object pObject = someRpcCall();
I don't know the type of pObject
What i know is System.out.println(pObject.toString()) outputs
{partner_shipping_id=12, partner_order_id=11, user_id=1, partner_invoice_id=13, pricelist_id=1, fiscal_position=false, payment_term=false}
How can I convert this pObject to object of the following class
import android.os.Parcel;
import android.os.Parcelable;
public class Customer implements Parcelable {
private int id;
private String name = "";
public Customer() {
// TODO Auto-generated constructor stub
}
/**
* This will be used only by the MyCreator
*
* #param source
*/
public Customer(Parcel source) {
/*
* Reconstruct from the Parcel
*/
id = source.readInt();
name = source.readString();
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
#Override
public Customer createFromParcel(Parcel source) {
return new Customer(source);
}
#Override
public Customer[] newArray(int size) {
return new Customer[size];
// TODO Auto-generated method stub
}
};
}
Whats the output of System.out.println(pObject.getClass().getName());
If its the same Customer class, then you could cast the object like this
Customer cust = (Customer) pObject;
The answer to the above problem is provided, but I have a generic solution which I want to share all of you.
First, fetch the class name using Object object(provided)
Using Enum know the Class name
Create a reference object of the known class
Initialize your Object class object
e.g:
package com.currentobject;
import com.currentobject.model.A;
import com.currentobject.model.B;
import com.currentobject.model.C;
Class CurrentObject{
public void objectProvider(Object object){
String className = object.getClass().getCanonicalName();
ModelclassName modelclass = ModelclassName.getOperationalName(className);
switch (modelclass) {
case A:
A a = (A) object;
break;
case B:
B b = (B) object;
break;
case C:
C c = (C) object;
break;
}
}
}
enum ModelclassName {
A("com.currentobject.model.A"),
B("com.currentobject.model.B"),
C("com.currentobject.model.C");
private ModelclassName(String name) {
this.name = name;
}
public static ModelclassName getOperationalName(final String operationName) {
for(ModelclassName oprname :ModelclassName.values()) {
if(oprname.name.equalsIgnoreCase(operationName)){
return oprname ;
}
}
return null;
}
String name;
}