I want to insert a value to an Object variable without using the setters. How can if be possible.
This is an example
Class X{
String variableName;
// getters and setters
}
Now i have a function which contains the variable name, the value to be set and an Object of the Class X.
I am trying to use a generic method to set the value to the Object(objectOfClass) with the value i have passed(valueToBeSet) in the corresponding variable(variableName).
Object functionName(String variableName, Object valueToBeSet, Object objectOfClass){
//I want to do the exact same thing as it does when setting the value using the below statement
//objectOfClass.setX(valueToBeSet);
return objectOfClass;
}
This code is not tested. You can try this.
Classes to import
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Method
public Object functionName(String variableName, Object valueToBeSet, Object objectOfClass) throws IntrospectionException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//I want to do the exact same thing as it does when setting the value using the below statement
//objectOfClass.setX(valueToBeSet);
Class clazz = objectOfClass.getClass();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class); // get bean info
PropertyDescriptor[] props = beanInfo.getPropertyDescriptors(); // gets all info about all properties of the class.
for (PropertyDescriptor descriptor : props) {
String property = descriptor.getDisplayName();
if(property.equals(variableName)) {
String setter = descriptor.getWriteMethod().getName();
Class parameterType = descriptor.getPropertyType();
Method setterMethod = clazz.getDeclaredMethod(setter, parameterType); //Using Method Reflection
setterMethod.invoke(objectOfClass, valueToBeSet);
}
}
return objectOfClass;
}
If you are sure that you really need this, please, think twice, but anyway:
import java.lang.reflect.Field;
...
X x = new X();
Field variableName = x.getClass().getDeclaredField("variableName");
// this is for private scope
variableName.setAccessible(true);
variableName.set(x, "some value");
There are two ways of setting values in object
1-Constructor Injection -- "Pushing" dependencies into a concrete class through constructor arguments.
2-Setter Injection -- "Pushing" dependencies into a concrete class through public properties. The "Setter" nomenclature is taken from Java where properties are getSomething() and setSomething(value).
As you don't want to use setters ,You can create a parameterised constructor to do so.Parameterized constructors are required to pass parameters on creation of objects.Except it I don't think that there is any other way of doing that without calling setters.
Related
I am trying to modify an object with an Arraylist of objects using reflection.
I understand that I cannot get the type of the objects in the ArrayList, but I (think) I am using an annotation to handle that part. I am setting the field accessibility.
I am declaring the list of stuff in the class using annotations.
#TableAnnotation(type = PhoneNumber.class)
protected List<PhoneNumber> phoneNumbers = new ArrayList<>();
#TableAnnotation(type = Address.class)
private List<Address> addresses= new ArrayList<>();
private List<Role> roles= new ArrayList<>();
... Later in the same class I try to set them:
public void setMemberTable(List<Table> tables, String memberName) throws IllegalAccessException {
Class t = getClass();
for (Field field : getClass().getDeclaredFields()) {
if (field.getName() == memberName) {
field.setAccessible(true);
List array = (List)field.get(this.getClass()); <<<=========== Here is where it is throwing
ArrayList arrayList= (ArrayList)field.get(this.getClass());
//array.add(tables.get(0));
System.out.println();
}
}
}
Here is the Annotation that seems to be working:
package com.test.database.helpers;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Documented
#Target(ElementType.FIELD)
#Inherited
#Retention(RetentionPolicy.RUNTIME)
public #interface TableAnnotation {
Class< ?> type();
boolean allowNull() default false;
}
This throws:
java.lang.IllegalArgumentException: Can not get java.util.List field com.test.database.entities.Person.phoneNumbers on java.lang.Class
I tried making the member variable public, but that had no affect.
I need help to be able to set the member variables in setMemberTable().
(List)field.get(this.getClass());
The .get method on j.l.reflect.Field requires the instance that you want to get the field from. You're passing the class. Which is an object of type java.lang.Class, which, of course, does not have this field, and therefore, you can't get the value of it. You want this instead.
Actually, none of this makes sense, you're right there, just read your own field. I assume this is test code, but if not, none of this makes sense in the first place.
You ask the wrong object for the value of the field.
When you write
field.get(this.getClass())
you try to get the value that the (reflected) field has on some instance. The object that you pass to retrieve the value from is this.getClass() which is an instance of java.lang.Class - and java.lang.Class has no field (for example) "phoneNumbers".
To retrieve a field from your instance you must write
field.get(this)
But then, the commented out line
array.add(tables.get(0));
doesn't make any sense. Why do you try to add an element from the tables list (which is an instance of Table) to a list of (for example) "phoneNumbers", which is a list of PhoneNumber?
And your claim that the annotation works: I don't see that annotation used anywhere in your code, so it is hard to say whether it works or not...
So the idea behind this is that I have a main class that is starting a Server (servlet) and I want to inject all the classes that servlet will need in the future so it doesn't instantiate them himself (considered bad practice ?)
I create an annotation ToInject to indicate the attributes within classes that will need to be injected for the whole system to work.
I call my injectionService right before I instantiate the servlet : InjectionService.injectObject(ServletMain.class) and my hope is that with the recursion it will instantiate and place the right objects at the right places.
I'm using a HashMap to keep the instances of each type of object I iterate over.
In my ServletMain class : instead of writing LoginController log = new LoginController(); I would write #ToInject LoginController log; .
Is this the right way to go ? It doesn't work right now but I can't see what I'm missing.
Edit/PS : the reason why I'm not using Spring-like tools is because the assignment doesn't allow us to use those.
I realize this is a very specific question, thank you in advance for the answers.
package utils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import domain.factory.IFactory;
public class InjectionService {
private static IFactory factory = null;
private static HashMap<Object, Object> map_class_instance = new HashMap<Object, Object>();
public static void injectObject(Object o) throws NoSuchMethodException, SecurityException,
ClassNotFoundException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Field[] fields = o.getClass().getDeclaredFields();
for (Field f : fields) {
if (f.isAnnotationPresent(ToInject.class)) {
if (map_class_instance.get(o) == null) {
Constructor cons = (Constructor) Class.forName((String) o).getDeclaredConstructor();
cons.setAccessible(true);
Object obj = cons.newInstance();
map_class_instance.put(o.getClass(), obj);
// recursif
f.set(o, map_class_instance.get(f));
injectObject(f);
}
f.set(o, map_class_instance.get(f));
injectObject(f);
}
}
}
I have an object that has a String field. I can obtain this field by calling:
Field field = someObj.getClass().getField("strField");
I sett a Field#set(Object) method, for setting the value of this instance's field, but the respective getter seems to be Field#get(Object), which is weird because I would have expected it to be Field#get().
How do I obtain the value of the instance's strField?
if you are using java.lang.reflect.Field, the "setter" is Field.set(Object,Object) and the "getter" is Field.get(Object). in both cases, the first parameter is the instance on which you want to access the field.
Even without the getter or the setter methods for a property, you can change or get the value using an object reference and Java Reflection.
import java.lang.reflect.Field;
public class Bean {
private String strField;
public static void main(String[] args) throws Exception {
Bean bean = new Bean();
Field field = bean.getClass().getDeclaredField("strField");
field.set(bean, "Hello");
System.out.println(field.get(bean));
}
}
Easiest way is to use BeanUtils:
String s = BeanUtils.getProperty(someObj, "strField");
Note that BeanUtils will attempt to convert your property into string. You need to have a getter and setter of the property
I have previously only used reflection to do things like dynamically get class and set field values in it. My Google search showed me that I could also possibly use reflection for dynamic type casting?
My code is as follows:
import entity.Shipvia;
import entity.Route;
import java.lang.reflect.Field;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.Query;
public class RetrieveResultList {
public static List retrieveResultList(String tablename) {
EntityManager entityManager = Persistence.createEntityManagerFactory("EntityLibraryPU").createEntityManager();
Query query = entityManager.createNamedQuery(tablename + ".findAll");
List<Shipvia> resultList = query.getResultList();
return resultList;
}
}
I am using this method to dynamically retrieve result from a database table. Because the table name is always different, I cannot have List as it will be different for each table.
How would I go about converting the tablename string that I am passing in, to be the type of the List?
You can't do that and even if you could, it would be useless as all generics information is removed from the Java code when it's compiled, only casts would be there and as you would be using reflection there would be no casts to be made.
The closest thing you will be able to do is, instead of sending in a String send a Class object. The caller code would have to say which class it wants (the caller probably knows what kind of object it's using) and you would use it to make the list have the correct generic.
A very simple implementation would be something like this:
List<Shipvia> shipvias = RetrieveResultList.retrieveResultList( Shipvia.class );
And implementation could be something like this:
public class RetrieveResultList {
private static final EntityManagerFactory FACTORY = Persistence.createEntityManagerFactory("EntityLibraryPU");
public static <T> List<T> retrieveResultList(Class<T> type) {
EntityManager entityManager = FACTORY.createEntityManager();
String tablename = type.getName(); // figure out table name from **type**
Query query = entityManager.createNamedQuery(tablename + ".findAll");
List<T> resultList = query.getResultList();
entityManager.close();
return resultList;
}
}
And then you should have something like what you're looking for.
ALSO, DO NOT create an entity manager factory on every call to this method, the entity manager factory MUST BE a singleton in your project as it's a very expensive object to create. You should also close the EntityManager you created before leaving the method.
I saw this question
Inject into private, package or public field or provide a setter?
about how to manually inject into annotated private fields (The way is adding setters
or through a constructor)
But, the point is how do an application server (like glassfish, axis2, jboss, ...)
is able to inject into a final private field (without adding setters or constructors
to the user class)?
Quoting the cited question:
public SomeClass {
#Inject
private SomeResource resource;
}
Do they use a customized JVM (not the standard one) that allows to access private fields?
Thanks
It's a simple reflection "trick". It relies on the Field.setAccessible() method to force the member to be accessible programmatically:
Set the accessible flag for this
object to the indicated boolean value.
A value of true indicates that the
reflected object should suppress Java
language access checking when it is
used. A value of false indicates that
the reflected object should enforce
Java language access checks.
The Reflection API is used to get a handle on the field, setAccessible() is called, and then it can be set by the injection framework.
See an example here.
No magic, no custom VM.
With the help of skaffman I coded this simple example on how to inject without setters.
Perhaps it helps (It did to me)
//......................................................
import java.lang.annotation.*;
import java.lang.reflect.*;
//......................................................
#Target(value = {ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#interface Inject {
}
//......................................................
class MyClass {
#Inject
private int theValue = 0;
public int getTheValue() {
return theValue;
}
} // class
//......................................................
public class Example {
//......................................................
private static void doTheInjection(MyClass u, int value) throws IllegalAccessException {
Field[] camps = u.getClass().getDeclaredFields();
System.out.println("------- fields : --------");
for (Field f : camps) {
System.out.println(" -> " + f.toString());
Annotation an = f.getAnnotation(Inject.class);
if (an != null) {
System.out.println(" found annotation: " + an.toString());
System.out.println(" injecting !");
f.setAccessible(true);
f.set(u, value);
f.setAccessible(false);
}
}
} // ()
//......................................................
public static void main(String[] args) throws Exception {
MyClass u = new MyClass();
doTheInjection(u, 23);
System.out.println(u.getTheValue());
} // main ()
} // class
Run output:
------- fields : --------
-> private int MyClass.theValue
found annotation: #Inject()
injecting !
23
It's also worth noting, that some frameworks utilize bytecode engineering via a custom classloader to achieve the same result without the cost of Reflection (reflection can be pretty expensive at times)