Say I have class AccountPojo and GetAccountPojo with its setter and getter methods as below.
public class AccountPojo {
private String dataList;
private String dataSet;
public String getDataList() {
return dataList;
}
public void setDataList(String dataList) {
this.dataList = dataList;
}
public String getDataSet() {
return dataSet;
}
public void setDataSet(String dataSet) {
this.dataSet = dataSet;
}
}
public class GetAccountsPojo {
private String accountId;
private int noOfAccounts;
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public int getNoOfAccounts() {
return noOfAccounts;
}
public void setNoOfAccounts(int noOfAccounts) {
this.noOfAccounts = noOfAccounts;
}
}
Now I have class Test as below
public Class Test {
public static void main(String[] args) {
Class cls = Class.forName("com.org.temp."+ClassName); // ClassName(AccountPojo/GetAccountPojo) here I know already which class is getting called.
Object clsInstance = (Object) cls.newInstance();
System.out.println("The cls is==" + cls+" and classInstance is=="+clsInstance);
// Here I want to access getter and setter methods of AccountPojo and GetAcoountPojo dynamically, no hard coding
}
}
Have you tried getting all the methods of the invoked class and filtering out only the getter methods by name and invoking them?
Method[] methods = cls.getClass().getDeclaredMethods();
for (Method m: methods) {
if(m.getName().startsWith("get")) {
m.invoke(clsInstance);
}
}
This solves our half problem, as getters are invoked without any arguments. But if you need to invoke a setter method you need to specify arguments. Ex, To invoke a setter which accepts string argument method as below:
m.invoke(clsInstance, "some string argument");
One solution to could be make all the setters accept an object type value and typecast them while assigning it to actual class variables.
Now your pojo classes will look as below:
public class AccountPojo {
private String dataList;
private String dataSet;
public String getDataList() {
return dataList;
}
public void setDataList(Object dataList) {
this.dataList = (String) dataList;
}
public String getDataSet() {
return dataSet;
}
public void setDataSet(Object dataSet) {
this.dataSet = (String)dataSet;
}
}
public class GetAccountsPojo {
private String accountId;
private int noOfAccounts;
public String getAccountId() {
return accountId;
}
public void setAccountId(Object accountId) {
this.accountId = (String) accountId;
}
public int getNoOfAccounts() {
return noOfAccounts;
}
public void setNoOfAccounts(Object noOfAccounts) {
this.noOfAccounts = (int) noOfAccounts;
}
}
Add below code to your main method:
for (Method m: methods) {
if(m.getName().startsWith("get")) {
m.invoke(clsInstance);
}
if(m.getName().startsWith("set")) {
m.invoke(clsInstance, "any argument to be passed here");
}
}
Don't use raw class. If you know which class is called already, use typed class.
try {
AccountPojo obj = AccountPojo.class.newInstance();
Method setDataList = AccountPojo.class.getMethod("setDataList");
setDataList.setAccessible(true); // This is important if you want to access protected or private method. For public method you can skip
setDataList.invoke(obj, "123");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Related
I have a class as follows:
public class MyClass {
#JsonProperty("my_id")
private String id;
#JsonProperty("my_list")
private List<SecondClass> myList;
public getId() {
return this.id;
}
public setId(String id) {
this.id = id;
}
public getMyList() {
return this.myList;
}
public setMyList(List<SecondClass> myList) {
this.myList = myList;
}
}
My class has a dependency on another class called SecondClass [through the List entity]
public class SecondClass {
#JsonProperty("my_name")
private String name;
public getName() {
return this.name;
}
public setName(String name) {
this.name = name;
}
}
I know how to access the getters and setters of "MyClass" using Reflection based on the JsonProperty name, as shown below:
public void myMethod(MyClass myClass, String jsonProperty, String newId) throws IllegalAccessException {
for (Field field : MyClass.class.getDeclaredFields()) {
JsonProperty jsonPropAnnotation = field.getAnnotation(JsonProperty.class);
if (jsonPropAnnotation != null)
if (jsonPropAnnotation.value().equals(jsonProperty)) {
field.setAccessible(true);
field.set(myClass, newId);
}
}
}
But, my question is, is there a way to fetch the getter and setter from SecondClass via MyClass based on the JsonProperty name using Reflection?
As an example I would like to call getList() based on JsonProperty value "my_list" and then setName() based on the JsonProperty value "my_name".
Is this a possibility using reflection?
I am not sure what you want to achieve and how you will pass the values to set but all this is possible. Please check below code piece for your problem.
If you can explain me the full requirement then may be I can help you in implementing the best solution but for this ask below code will also work -
public class Main {
public static void main(String[] args) throws IllegalAccessException {
MyClass myClass = new MyClass();
List<SecondClass> secondClasses = new ArrayList<>();
myClass.setId("1234");
SecondClass sc1 = new SecondClass();
sc1.setName("Name1");
secondClasses.add(sc1);
myMethod(myClass, "my_id", "1234");
System.out.println(myClass.getId());
for (SecondClass secondClass : secondClasses) {
SecondClass secondClass1 = new SecondClass();
myMethod(secondClass1, "my_name", secondClass);
System.out.println(secondClass1.getName());
}
}
public static void myMethod(Object object, String jsonProperty, Object value) throws IllegalAccessException {
for (Field field : object.getClass().getDeclaredFields()) {
JsonProperty jsonPropAnnotation = field.getAnnotation(JsonProperty.class);
if (jsonPropAnnotation != null)
if (jsonPropAnnotation.value().equals(jsonProperty)) {
if (field.getType().equals(String.class) || field.getType().equals(Double.class)) {
field.setAccessible(true);
if (value.getClass().equals(String.class)) {
field.set(object, value);
}else{
field.set(object, field.get(value));
}
}
}
}
}
}
i want use reflection on generic type
i have this class
package it.ciro.service;
import it.ciro.dao.SysMyAbDao;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ciro on 09/12/2016.
*/
public class SelectOption<E extends Serializable> {
private SysMyAbDao dao;
private Class<E> entity;
private ArrayList<Class<E>> entityAll;
private Map<String,String> optionList = new HashMap<String,String>();
protected Logger logger;
public SelectOption(SysMyAbDao dao,Class<E> entity,String idName, String labelName ){
logger = Logger.getLogger(this.getClass());
this.dao = dao;
this.entity = entity;
entityAll = dao.findAll();
try{
Method idMethod = this.entity.getMethod(idName);
Method labelMethod = this.entity.getClass().getMethod(labelName);
for (Class<E> single : entityAll) {
optionList.put((String)idMethod.invoke(single),(String)labelMethod.invoke(single));
}
}catch (NoSuchMethodException ex){
ex.printStackTrace();
logger.error(ex.getMessage());
} catch (InvocationTargetException e) {
logger.error(e.getMessage());
} catch (IllegalAccessException e) {
logger.error(e.getMessage());
}
}
public Map<String, String> getOptionList() {
return optionList;
}
}
and in my controller
SelectOption<GeoProvince> selectOption = new SelectOption(geoRegionDao,GeoRegion.class,"idGeoRegion","name");
but i get
java.lang.NoSuchMethodException: java.lang.Class.idGeoRegion()
java search on generic type e not on type that I use in constructor
I expect the search to be made about the type I spend in controller. In GeoRegion class the method exists.
this is SysMyAbDao
public abstract class SysMyAbDao<T, E, Id extends Serializable> {
protected String message;
protected Boolean status;
protected T t ;
protected Logger logger;
protected Long totalRow;
private Class<T> type;
public SysMyAbDao(Class<T> type){
this.type = type;
}
.....
GeoRegion class
public class GeoRegion implements java.io.Serializable {
private int idRegion;
private String name;
private String code;
private Set<GeoProvince> geoProvinces = new HashSet<GeoProvince>(0);
private Set<GeoCity> geoCities = new HashSet<GeoCity>(0);
public GeoRegion() {
}
public GeoRegion(int idRegion) {
this.idRegion = idRegion;
}
public GeoRegion(int idRegion, String name, String code, Set<GeoProvince> geoProvinces, Set<GeoCity> geoCities) {
this.idRegion = idRegion;
this.name = name;
this.code = code;
this.geoProvinces = geoProvinces;
this.geoCities = geoCities;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id_region", unique=true, nullable=false)
public int getIdRegion() {
return this.idRegion;
}
public void setIdRegion(int idRegion) {
this.idRegion = idRegion;
}
#Column(name="name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#Column(name="code", unique=true)
public String getCode() {
return this.code;
}
public void setCode(String code) {
this.code = code;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="geoRegion")
public Set<GeoProvince> getGeoProvinces() {
return this.geoProvinces;
}
public void setGeoProvinces(Set<GeoProvince> geoProvinces) {
this.geoProvinces = geoProvinces;
}
#OneToMany(fetch=FetchType.LAZY, mappedBy="geoRegion")
public Set<GeoCity> getGeoCities() {
return this.geoCities;
}
public void setGeoCities(Set<GeoCity> geoCities) {
this.geoCities = geoCities;
}
}
You have an extra getClass() in this line:
Method labelMethod = this.entity.getClass().getMethod(labelName);
In fact, you are calling getClass() on the Class<E> object. And as the class of Class<E> is not E but java.lang.Class you get the NoSuchMethodException you posted.
Also the instance which you are invoking your method on (single in your case), should be of type E and not of type Class<E>.
Overall you would end up with something like:
public SelectOption(SysMyAbDao<E, ?, ? extends Serializable> dao,
Class<E> entityClass,
String idName,
String labelName) {
this.dao = dao;
this.entityClass = entityClass;
this.entityAll = dao.findAll(); // make sure your SysMyAbDao<E, ?, ?>#findAll() returns a Collection<E>
try{
Method idMethod = this.entityClass.getMethod(idName);
Method labelMethod = this.entityClass.getMethod(labelName);
for (E instance : entityAll) {
optionList.put((String)idMethod.invoke(instance),(String)labelMethod.invoke(instance));
}
} catch (NoSuchMethodException ex){
...
}
}
You are trying to invoke your method on single, which is a Class object.
I don't see any instances of GeoRegion in this code. But in order for this to work, you need to use this method on one of them:
E instance = getSomeObjectFromSomewhere();
optionList.put((String)idMethod.invoke(instance),(String)labelMethod.invoke(instance));
I am wondering how can I define protected, public and private properties in my class GenericBean, which will result in a JavaBean. So far I've declared a class, that will enable use to access the value of the Bean, however, I have no idea how I can handle different accesses for those properties. Any idea? Here is m y class:
abstract class GenericBean {
protected PropertyChangeSupport chg = new PropertyChangeSupport(this);
protected VetoableChangeSupport veto = new VetoableChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener pcl) {
chg.addPropertyChangeListener(pcl);
}
public void removePropertyChangeListener(PropertyChangeListener pcl) {
chg.addPropertyChangeListener(pcl);
}
class BoundedProperty<T> implements PropertyChangeListener {
private String name;
private T value;
private Object chgHandlerObject;
private Method changeHandler;
public BoundedProperty(String name) {
this.name = name;
}
public T getValue() { return value; }
public void setValue(T newValue) {
T old = value;
value = newValue;
chg.firePropertyChange(name, old, value);
}
public void propertyChange(PropertyChangeEvent e) {
if (!e.getPropertyName().equals(name)) return;
if (changeHandler == null) return;
try {
changeHandler.invoke(chgHandlerObject);
} catch(Exception exc) {
exc.printStackTrace();
}
}
public void setChangeHandler(Object handl, String mname) {
try {
Method m = handl.getClass().getDeclaredMethod(mname);
chgHandlerObject = handl;
changeHandler = m;
chg.addPropertyChangeListener(this);
} catch(Exception exc) {
exc.printStackTrace();
return;
}
}
public void setChangeHandler(Object ohandler) {
try {
Method m = ohandler.getClass().getDeclaredMethod(name+"Change");
chgHandlerObject = ohandler;
changeHandler = m;
} catch(Exception exc) {
exc.printStackTrace();
return;
}
chg.addPropertyChangeListener(this);
}
public void removeChangeHandler() {
changeHandler = null;
chgHandlerObject = null;
chg.removePropertyChangeListener(this);
}
}
}
So that I can decide which methods are available for certain fields?
I am trying to assign the value returned by some function to a field in the deserialized class of json.
FileInfo.java
public class FileInfo {
#SerializedName("Name")
private String mName;
#SerializedName("Url")
private String mUri;
#SerializedName("Size")
private Integer mSize;
#SerializedName("ModTime")
private Long mModifiedTime;
private FileType mType;
#SerializedName("Children")
private ArrayList<FileInfo> mChildren = new ArrayList<>();
public ArrayList<FileInfo> getChildren() {
return mChildren;
}
public long getModifiedTime() {
return mModifiedTime;
}
public String getName() {
return mName;
}
public Integer getSize() {
return mSize;
}
public String getUrl() {
return mUri;
}
public FileType getType() {
return mType;
}
public void setChildren(ArrayList<FileInfo> mChildren) {
this.mChildren = mChildren;
}
public void setModifiedTime(long mModifiedTime) {
this.mModifiedTime = mModifiedTime;
}
public void setName(String mName) {
this.mName = mName;
}
public void setSize(Integer mSize) {
this.mSize = mSize;
}
public void setType(FileType mType) {
this.mType = mType;
}
public void setUri(String mUri) {
this.mUri = mUri;
}
#Override
public String toString() {
return FileInfo.class.toString();
}
public FileInfo() {
}
}
The mType needs to be assigned to foo(mName). I looked up custom deserializers and instance creators but none of those helped. I also thought of TypeAdapters which i feel defeats the purpose of keeping deserialization(using GSON) simple.
This is a sample JSON string that will be deserialized.
[
{
"Name":"Airport",
"Url":"http://192.168.2.2/api/sites/Baltimore%20Airport/Airport",
"Size":0,
"ModTime":"2015-12-02T14:19:17.29824-05:00",
"Children":null
}
]
P.S. I'm not sure if this should be done during deserialization but trying anyways. Also please let me know of alternative ways to achieve this.
I have a question regarding reflection in Java.
Following problem:
Depending on a configuration I want to call a method via reflection, but not only of a class CLASS_A, but also from a class CLASS_B that is referenced by CLASS_A.
But I want to use always only class CLASS_A to access the attribute.
Here an example what I mean:
public class Foo
{
private String _name;
private Bar _bar;
public Foo(String name, Bar bar)
{
_name = name;
_bar = bar;
}
public String getName()
{
return _name;
}
public Bar getBar()
{
return _name;
}
}
public class Bar
{
private String _name;
public Bar(String name)
{
_name = name;
}
public String getName()
{
return _name;
}
}
I want to use always an instance of class Foo to invoke the method that is returned by getMethod ... no matter whether the method of Foo should be called or the method of Bar.
public class Executor
{
public static void main(String[] args)
{
Foo foo = new Foo("fooName", new Bar("barName"));
String attribute = "barName";
Method method = getMethod(Foo.class, attribute);
try
{
System.out.println(String.valueOf(method.invoke(foo, new Object[]{})));
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
private static Method getMethod(Class< ? > clazz, String attribute)
{
try
{
if (attribute.equals("fooName"))
{
return clazz.getDeclaredMethod("getName", new Class[] {});
}
else if (attribute.equals("barName"))
{
//Is that somehow possible?
Method method = clazz.getDeclaredMethod("getBar.getName", new Class[] {});
return method;
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
}
Is something like that possible?
Thanks!
You can use Apache BeanUtils library.
Here is a good example of how you can use it.