Is there any way to cast from Field to an Object? [duplicate] - java

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

Related

trying to set a member ArrayList using reflection

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...

Invoke method using spring SPEL with property

Is it possible to use a property value to invoke a method while assigning a value?
For instance, I know I can do this:
#Value("${name}")
private String name; // will have the value of the `name` property
I wonder if it's possible to do something like this:
#Value("#{myMethod(${name})}")
private String myModifiedVariable; // will have the result of invoking myMethod
After my research and a bit of testing, I found there is a way shown in this article Spring EL method invocation, But mybean should be a string bean
#Value("#{mybean.myMethod('${name}')}")
private String myModifiedVariable;
And if you want to call a method in the existing class then use the spring bean name of the same class
#Configuration // or any sterotype annoations
public class TestConfig {
#Value("#{testConfig.myMethod('${name}')}")
private String myModifiedVariable;
public String getValue(String val){
return val+"testValue";
}
}
When using interface projection (in Spring Data Repository) it is possible to call a static method like this:
public interface MyProjection {
// Here we are creating a 2 element list with 'Spring Data' and value taken from "MY_COLUMN_NAME" column
#Value("#{T(java.util.Arrays).asList('Spring Data', target.MY_COLUMN_NAME)}")
List<String> getSampleList();
}
You can also obtain a value of an enum (constant) with above notation. Sample for Spring Security check:
#PreAuthorize("hasRole(T(com.acme.UserRoles).ADMINISTRATOR.name())")
Similar notation should work in other places. Simply remember to use full path to class

How to set values to a class variables without using setters

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.

Java annotation to set field to a static instance?

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.

Use #JacksonInject with #JsonCreator on a top level map

With Jackson json library, it is possible to deserialize object through the use of the #JsonCreator, and be given the "top level" map representing the input json, as follows:
class MyClass {
final int field;
#JsonCreator
public MyClass(Map<String, Object> map) {
this.field = (int) map.get("theInt");
}
}
or even on a static factory method:
class MyClass {
final int field;
public MyClass(int theInt) {
this.field = theInt;
}
#JsonCreator
static MyClass create(Map<String, Object> map) {
return new MyClass((int) map.get("theInt"));
}
}
The previous examples can process the following kind of json input:
{
"key1":"value1",
"key2":"value2",
"key3":"value3"
}
This is particularly useful in my case because I would like to deserialize a json which structure I don't know. Being given access to what I call the "top level map" makes things simple.
I would like to deserialize my objects this way as it also allows to create immutable objects, instead of using #JsonAnySetter which doesn't permit this, and #JsonProperty which I can't use as I don't know the properties name in advance as I mentioned earlier.
Then to go further, I would like to inject some configuration in my factory method, and Jackson allows this through the use of #JacksonInject and a call to withInjectableValues(InjectableValues) on the ObjectMapper.
This is eventually the kind of code I would like to use:
class MyClass {
final MyField[] myFields;
public MyClass(MyField... myFields) {
this.myFields = myFields;
}
#JsonCreator
static MyClass create(#JacksonInject("conf") Conf conf, Map<String, Object> map) {
MyFields[] myFields;
// initialize myFields (or any other object) based on the content of map
// and also make use of the inject conf
return new MyClass(myFields);
}
}
Unfortunately, Jackson throws the following kind of exceptions:
when trying the trick on the constructor
JsonMappingException: Argument #1 of constructor [constructor for MyClass, annotations: {JsonCreator=#JsonCreator()}] has no property name annotation; must have name when multiple-paramater constructor annotated as Creator
when trying the trick on the factory method
JsonMappingException: Argument #1 of factory method [method create, annotations: {JsonCreator=#JsonCreator()}] has no property name annotation; must have when multiple-paramater static method annotated as Creator
Does anyone know how I could solve the problem?
To sum up the requirements, I need:
access to the top level map (don't know the json property names in advance)
to create an immutable object (so can't use #JsonAnySetter)
to inject some conf to the #JsonCreator decorated constructor or factory method
I cannot change the json input format, which looks like this:
{
"key1":"value1",
"key2":"value2",
"key3":"value3"
}
[EDIT]
This is a known issue: http://jira.codehaus.org/browse/JACKSON-711 (not fixed yet)
Right, you would like to both use "delegating" creator (single argument, into which JSON input is first bound) -- different from "property-based" creator where set of named parameters are passed -- and injectable value(s). This should ideally work, but I think it might not work currently.
I think there is a Jira entered for this, so you can check it (http://jira.codehaus.org/browse/JACKSON) out.
Just to make sure: are you using version 1.9.2? There have been some fixes in this are since 1.9.0; which at least would give better error message.

Categories

Resources