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...
Related
This code can check whether a class is deprecated or not
#Deprecated
public classRetentionPolicyExample{
public static void main(String[] args){
boolean isDeprecated=false;
if(RetentionPolicyExample.class.getAnnotations().length>0){
isDeprecated= RetentionPolicyExample.class
.getAnnotations()[0].toString()
.contains("Deprecated");
}
System.out.println("is deprecated:"+ isDeprecated);
}
}
But, how can be checked if any variable is annotated as deprecated?
#Deprecated
Stringvariable;
import java.util.stream.Stream;
Field[] fields = RetentionPolicyExample.class // Get the class
.getDeclaredFields(); // Get its fields
boolean isAnyDeprecated = Stream.of(fields) // Iterate over fields
// If it is deprecated, this gets the annotation.
// Else, null
.map(field -> field.getAnnotation(Deprecated.class))
.anyMatch(x -> x != null); // Is there a deprecated annotation somewhere?
You are checking the Class annotations. The reflection API's also give you access to Field and Method annotations.
See
Class.getFields() and Class.getDeclaredFields()
Class.getMethods() and Class.getDeclaredMethods()
Class.getSuperClass()
A couple of problems with your implementation
You are only checking getAnnotations[0] when there might be more than one annotation
You are testing toString().contains("Deprecated") when you should check .equals(Deprecated.class)
You could use .getAnnotation(Deprecated.class)
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 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.
I've been playing with annotations, and I'm wondering how to go about doing this. What I'd like to do is to be able to have a field declared in a class and annotated such that the field will be initialized with a static instance of the class.
Given an annotation like this:
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME) //or would this be RetentionPolicy.CLASS?
public #interface SetThisField {
}
Something like this:
public class Foo {
#SetThisField
private Bar bar;
}
I've played around with using a parser and setting this at runtime, which works but isn't as elegant as I'd like.
I can't find any really good examples of RetentionPolicy.CLASS but the documentation seems to indicate that I could somehow make the declaration of "bar" get compiled into this:
private Bar bar = Bar.getInstance();
It wouldn't look that way in the source code of course, but it would in the byte code and it would behave like that at runtime.
So am I off base here? Is this possible? Or is the parser the way to go with it?
UPDATE: This is the guts of the parser I'm using
public static void parse(Object instance) throws Exception {
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
//"Property" annotated fields get set to an application.properties value
//using the value of the annotation as the key into the properties
if (field.isAnnotationPresent(Property.class)) {
Property property = field.getAnnotation(Property.class);
String value = property.value();
if (!"".equals(value)) {
setFieldValue(instance, field, properties.getProperty(value));
}
}
//"Resource" annotated fields get static instances of the class allocated
//based upon the type of the field.
if (field.isAnnotationPresent(Resource.class)) {
String name = field.getType().getName();
setFieldValue(instance, field, MyApplication.getResources().get(name));
}
}
}
private static void setFieldValue(Object instance, Field field, Object value) throws IllegalAccessException {
boolean accessibleState = field.isAccessible();
field.setAccessible(true);
field.set(instance, value);
field.setAccessible(accessibleState);
}
I would suggest doing the replacement at run time. This is much simpler to implement and test. Changing the byte code at build time is relatively error prone and tricky to get right. For example you would need to understand how byte code is structured and in this case how to add the code to all the constructors in the right place in the code.
If you make the retention RUNTIME, you can have a library which examines the annotation and sets the value after the object is created.
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.