I need to get private fields from one class and set them to another class.
This code works perfectly well for test Integer fields (100500 value gets written):
//get objects, class firs...
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, new Integer(100500));
}
Nontheless, when I switch to undefined type (the fields are of DIFFERENT types: Dates, Integers, Strings...
Eg class one has Date and class two has Date, I need to copy one value from another, but next field is going to be String in both classes)
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, field1);
}
I receive an IllegalArgumentException, e.g. I am not really able to get the values from one class and set it into another.
Please, dear community, give me a hint - what am I doing wrong?
to me, it looks like you hand over the field-reference instead of the field-value:
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, field1.get(app1)); //or whatever object field1 is from
}
though i would not do it that way because order is a fragile thing...
you could use beanutils to copy your beans, if it is, what you want to achieve
This should suit your needs:
public static <T> void copyDeclaredFields(T from, T to) throws Exception {
Class<?> clazz = from.getClass();
if (!clazz.equals(to.getClass())) {
throw new IllegalArgumentException();
}
for (Field field : clazz.getDeclaredFields()) {
Object value = field.get(from);
field.set(to, value);
}
}
To call:
Item item1 = new Item();
// item1.set...
Item item2 = new Item();
copyDeclaredFields(item1, item2);
Your error seems to be related to the fact that you are trying to set Field1 as parameter of Field, instead of the value of Field1.
field.set(app, field1);
should instead be
field.set(app, field1.get(app1));
Take a look at a small working example;
If you change
fieldDest.set(destination, fieldSrc.get(source));
to
fieldDest.set(destination, fieldSrc);
you will get the same error of this question.
Hope that helps.
Code of the example:
import java.util.*;
import java.lang.*;
import java.lang.reflect.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
Source source = new Source();
Destination destination = new Destination();
Class sourceClassObject = source.getClass();
Class destClassObject = destination.getClass();
Field[] sourceFields = sourceClassObject.getDeclaredFields();
Field[] destFields = destClassObject.getDeclaredFields();
for (Field fieldSrc : sourceFields) {
int mod = fieldSrc.getModifiers(); // get modifiers
System.out.print("Source Field: " + Modifier.toString(mod) + " "
+ fieldSrc.getType() + " " + fieldSrc.getName());
fieldSrc.setAccessible(true);
System.out.println(" [" + fieldSrc.get(source) + "]");
for (Field fieldDest : destFields){
if (fieldDest.getType().equals(fieldSrc.getType()) &&
fieldDest.getName().equals(fieldSrc.getName())){
fieldDest.setAccessible(true);
fieldDest.set(destination, fieldSrc.get(source));
}
}
}
destination.printValues();
}
static class Source{
public Source(){
strField = "This is a String";
intField = 42;
dateField = new Date();
}
private String strField;
private Integer intField;
private Date dateField;
}
static class Destination{
private String strField;
private Integer intField;
private Date dateField;
public void printValues(){
System.out.println("Destination Field values: ");
System.out.println("strField: " + strField);
System.out.println("intField: " + intField);
System.out.println("dateField: " + dateField);
}
}
}
Related
I am working on a Java class that contains a ton of numeric fields. Most of them would begin with something like 'CMTH' or 'FYTD'. Is it possible to initialize all fields of the same type that begin or end with a certain value. For example I have the following fields:
CMthRepCaseACR CMthRepUnitACR CMthRecCaseACR CMthRecUnitACR CMthHecCaseACR CMthHecUnitACR FYTDHecCaseACR FYTDHecUnitACR CMthBBKCaseACR CMthBBKUnitACR CMthPIHCaseACR .
I am trying to figure if it is possible to initialize all fields to zero that end with an 'ACR' or begin with an 'Cmth"
I know I can do something like cmtha = cmthb = cmthc = 0 but I was wondering there was a command where you can some kind of mask to initialize
Thanks
Assuming that you cannot change that said Java class (and e.g. use a collection or map to store the values) your best bet is probably reflection (see also: Trail: The Reflection API). Reflection gives you access to all fields of the class and you can then implement whatever matching you'd like.
Here's a short demo to get you started, minus error handling, sanity checks and adaptions to your actual class:
import java.util.stream.Stream;
public class Demo {
private static class DemoClass {
private int repCaseACR = 1;
private int CMthRepUnit = 2;
private int foo = 3;
private int bar = 4;
#Override
public String toString() {
return "DemoClass [repCaseACR=" + repCaseACR + ", CMthRepUnit=" + CMthRepUnit + ", foo=" + foo + ", bar="
+ bar + "]";
}
}
public static void main(String[] args) {
DemoClass demoClass = new DemoClass();
System.out.println("before: " + demoClass);
resetFields(demoClass, "CMth", null);
System.out.println("after prefix reset: " + demoClass);
resetFields(demoClass, null, "ACR");
System.out.println("after suffix reset: " + demoClass);
}
private static void resetFields(DemoClass instance, String prefix, String suffix) {
Stream.of(instance.getClass().getDeclaredFields())
.filter(field ->
(prefix != null && field.getName().startsWith(prefix))
|| (suffix != null && field.getName().endsWith(suffix)))
.forEach(field -> {
field.setAccessible(true);
try {
field.set(instance, 0);
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO handle me
}
});
}
}
Output:
before: DemoClass [repCaseACR=1, CMthRepUnit=2, foo=3, bar=4]
after prefix reset: DemoClass [repCaseACR=1, CMthRepUnit=0, foo=3, bar=4]
after suffix reset: DemoClass [repCaseACR=0, CMthRepUnit=0, foo=3, bar=4]
Note: Both links are seriously dated but the core functionality of reflection is still the same.
I try make class which generate new className.java file using reflection. I have problem with Fields value.
Here is my test class.
public class ClassTest {
#Deprecated
private int a;
public int[] b;
private final String c = "Hi";
...
}
Method in which I try generate fields.
private void writeAttributes(Class<?> cls, PrintWriter writer){
Field[] atr = cls.getDeclaredFields();
for (Field field : atr) {
this.writeAnnotations(writer, field.getDeclaredAnnotations());
writer.write(Modifier.toString(field.getModifiers())+" " + field.getType().getTypeName()+ " " + field.getName());
try{
System.out.println(field);
// NULL POINTER EXCEPTION there
Object value = field.get(null);
if(value!= null){
writer.write(" = " + value.toString());
}
}catch(IllegalAccessException ex){
}
writer.write(";");
this.writeNewLine(writer);
}
}
Error is on third field private final String c = "Hi";
Exception in thread "main" java.lang.NullPointerException
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:57)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
I have tried add field.setAccessible(true); but with there error comes on second field. Any ideas what is bad?
Since this is an instance field, you will need to pass an instance of the class to the get method:
get(clsInstance);
The documentation is actually pretty clear about that:
Throws NullPointerException - if the specified object is null and the field is an instance field.
You cannot access private fields by using .getDeclaredFields(). You can only access the public fields.
I've got two UnitTest projects for my Android project. One for the JUnit Test and one for the Android Unit Tests. In the JUnit Test Project I've made a class to access or set private fields, methods or constructors. (PS: For the ones that are curious of the complete code, let me know and I'll add it to the bottom of this post.)
I also have UnitTests to test these private-method accessing. Right now all of these UnitTests work, accept for one: Setting the value of a final static field.
This is the method I use for setting a private field:
// Test method to set a private Field from a class
public static void setPrivateField(Object ob, String fieldName, Object value) throws MyUnitTestException{
try {
Field field = ob.getClass().getDeclaredField(fieldName);
if(field != null){
field.setAccessible(true);
if(Modifier.isFinal(field.getModifiers())){
Field modifierField = Field.class.getDeclaredField("modifiers");
modifierField.setAccessible(true);
modifierField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
/*int modifiers = field.getModifiers();
Field modifierField = field.getClass().getDeclaredField("modifiers");
modifiers = modifiers & ~Modifier.FINAL;
modifierField.setAccessible(true);
modifierField.setInt(field, modifiers);*/
}
// ** IllegalAccessException at the following line with final static fields:
field.set(ob, value); // static fields ignore the given Object-parameter
}
}
catch (NoSuchFieldException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex){
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex){
throw new MyUnitTestException(ex);
}
}
And this is the UnitTest:
#Test
public void testSetIntFields(){
MyClass myClassInstance = new MyClass();
final int value = 5;
for(int nr = 1; nr <= 4; nr++){
String nameOfField = "myInt" + nr;
try {
TestMethodsClass.setPrivateField(myClassInstance, nameOfField, value);
}
catch (MyUnitTestException ex) {
Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}
int x = myClassInstance.getMyInt(nr);
Assert.assertTrue("myInt " + nr + " should be above 0", x > 0);
Assert.assertEquals("myInt " + nr + " should equal the set value (" + value + ")", value, x);
}
}
With the following MyClass:
#SuppressWarnings("unused")
public class MyClass
{
private int myInt1 = 0;
private static int myInt2 = 0;
private final int myInt3 = 0;
private static final int myInt4 = 0;
public MyClass(){ }
public int getInt(int nr){
switch(nr){
case 1:
return myInt1;
case 2:
return myInt2;
case 3:
return myInt3;
case 4:
return myInt4;
}
return -1;
}
}
(And the following MyUnitTestException):
public class MyUnitTestException extends Exception
{
private static final long serialVersionUID = 1L;
private Throwable thrownException;
public MyUnitTestException(Throwable ex){
super(ex);
thrownException = ex;
}
public String getThrownException(){
if(thrownException != null)
return thrownException.getClass().getName();
else
return null;
}
}
Setting the value to the fields myInt1, myInt2 and myInt3 works, but at myInt4 I'm getting an IllegalAccessException.
Does anyone know how I should fix this in my setPrivateField method? So it can not only set private, private static and private final fields, but also private static final ones.
EDIT 1:
After reading this article Forbidden Java actions: updating final and static final fields about in-lining at RunTime, I modified my UnitTest to this:
#Test
public void testSetIntFields(){
MyClass myClassInstance = new MyClass();
final int value = 5;
for(int nr = 1; nr <= 4; nr++){
String nameOfField = "myInt" + nr;
try {
TestMethodsClass.setPrivateField(myClassInstance, nameOfField, value);
}
catch (MyUnitTestException ex) {
Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}
// Get the set value using reflection
// WARNING: Since at RunTime in-lining occurs, we never use a Getter to test the set value, but instead use reflection again
int x = -1;
try {
x = (Integer)TestMethodsClass.getPrivateField(myClassInstance, nameOfField);
}
catch (MyUnitTestException ex) {
Assert.fail("getPrivateField caused an Exception: " + ex.getThrownException());
}
Assert.assertTrue("myInt " + nr + " should be above 0", x > 0);
Assert.assertEquals("myInt " + nr + " should equal the set value (" + value + ")", value, x);
}
}
(And this is my getPrivateField method, which is already completely tested and works):
// Test method to access a private Field from a class
public static Object getPrivateField(Object ob, String fieldName) throws MyUnitTestException{
Object returnObject = null;
try {
Field field = ob.getClass().getDeclaredField(fieldName);
if(field != null){
field.setAccessible(true);
returnObject = field.get(ob); // static fields ignore the given Object-parameter
}
}
catch (NoSuchFieldException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalAccessException ex) {
throw new MyUnitTestException(ex);
}
catch (IllegalArgumentException ex) {
throw new MyUnitTestException(ex);
}
return returnObject;
}
But I still get the same error.
EDIT 2:
Because I was using a getPrivateField in a UnitTest above it and tested all my UnitTests at the same time, it didn't worked. When I tested the UnitTest above separately it did work.. So I removed the getPrivateField-UnitTests (since in the code above I use both the Set and Get in one test) and now it does work.
I know this is very bad practice for UnitTests, but changing a private static final field during RunTime is already bad practice anyway. I just made the class to get and set private fields, methods and constructors, because I needed it about 3-4 times in some of my UnitTests and then I was just curious how far you can go with reflection and created a TestCase for everything I could think of. (Personally I find it a bit too far though.)
WARNING: Do not use reflection in any other case than tests. I don't recommend using it in your normal project, unless you've tried every other possible way. (I can't even think of a situation where you'd want to use reflection in your project, apart from tests.)
A primitive static final field is treated specially.
It is inlined as a constant by the compiler. The final executable does not access the field at runtime anymore.
A static final field is special-cased in the compiler, as its allowed to be inlined into any method that calls it.
It may not even exist in the end code.
static final int TEN = 10; // removed at compile time
int twenty() {
return TEN * 2; // compiler will turn this into 10*2 (and then probably 20 directly)
}
I am trying to obtain a field's value via reflection. The problem is I don't know the field's type and have to decide it while getting the value.
This code results with this exception:
Can not set java.lang.String field com....fieldName to java.lang.String
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();
Object value = field.get(objectValue);
I tried to cast, but I get compilation errors:
field.get((targetType)objectValue)
or
targetType objectValue = targetType.newInstance();
How can I do this?
Like answered before, you should use:
Object value = field.get(objectInstance);
Another way, which is sometimes prefered, is calling the getter dynamically. example code:
public static Object runGetter(Field field, BaseValidationObject o)
{
// MZ: Find the correct method
for (Method method : o.getMethods())
{
if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
{
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
{
// MZ: Method found, run it
try
{
return method.invoke(o);
}
catch (IllegalAccessException e)
{
Logger.fatal("Could not determine method: " + method.getName());
}
catch (InvocationTargetException e)
{
Logger.fatal("Could not determine method: " + method.getName());
}
}
}
}
return null;
}
Also be aware that when your class inherits from another class, you need to recursively determine the Field. for instance, to fetch all Fields of a given class;
for (Class<?> c = someClass; c != null; c = c.getSuperclass())
{
Field[] fields = c.getDeclaredFields();
for (Field classField : fields)
{
result.add(classField);
}
}
You should pass the object to get method of the field, so
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(object);
I use the reflections in the toString() implementation of my preference class to see the class members and values (simple and quick debugging).
The simplified code I'm using:
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
Class<?> thisClass = null;
try {
thisClass = Class.forName(this.getClass().getName());
Field[] aClassFields = thisClass.getDeclaredFields();
sb.append(this.getClass().getSimpleName() + " [ ");
for(Field f : aClassFields){
String fName = f.getName();
sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
}
sb.append("]");
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
I hope that it will help someone, because I also have searched.
Although it's not really clear to me what you're trying to achieve, I spotted an obvious error in your code:
Field.get() expects the object which contains the field as argument, not some (possible) value of that field. So you should have field.get(object).
Since you appear to be looking for the field value, you can obtain that as:
Object objectValue = field.get(object);
No need to instantiate the field type and create some empty/default value; or maybe there's something I missed.
Integer typeValue = 0;
try {
Class<Types> types = Types.class;
java.lang.reflect.Field field = types.getDeclaredField("Type");
field.setAccessible(true);
Object value = field.get(types);
typeValue = (Integer) value;
} catch (Exception e) {
e.printStackTrace();
}
`
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`
I post my solution in Kotlin, but it can work with java objects as well.
I create a function extension so any object can use this function.
fun Any.iterateOverComponents() {
val fields = this.javaClass.declaredFields
fields.forEachIndexed { i, field ->
fields[i].isAccessible = true
// get value of the fields
val value = fields[i].get(this)
// print result
Log.w("Msg", "Value of Field "
+ fields[i].name
+ " is " + value)
}}
Take a look at this webpage: https://www.geeksforgeeks.org/field-get-method-in-java-with-examples/
Was able to access private fields in a class using following method
Beneficiary ben = new Beneficiary();//class with multiple fields
ben.setName("Ashok");//is set by a setter
//then to get that value following was the code which worked for me
Field[] fields = ben.getClass().getDeclaredFields();
for(Field field: fields) {
field.setAccessible(true);//to access private fields
System.out.println(field.get(ben));//to get value
//assign value for the same field.set(ben, "Y");//to set value
}
You are calling get with the wrong argument.
It should be:
Object value = field.get(object);
Is there a way to access get the name of the view-reference as a String by means of Reflection or generating it?
Example:
public static final int main = 0x7f030000;
I have 0x7f030000, i want "main";
Field[] fields = R.layout.class.getDeclaredFields();
for(Field f : fields)
{
String fieldName = f.getName();
int fieldValue = (Integer) f.get(new Integer(0));
// ...
}