Sourabh
Sourabh

Reputation: 1303

Retrieving the data type for an object using reflection

I have an object initialized like :

Object obj  = new Object(){
  final String type = "java.lang.Integer";
  final Object value = 6;
};

I want to recreate this object as :

 Integer i = 6;

Is there any way I can get the type field of obj object and create a new instance using reflection and feed the value in it?

EDIT : Upon extending this question, I find that if I have the object stored in file and retrieve it from file using Jackson using this :

Reader reader = new Reader();
MyClass[] instances = reader.readValue(fileName);

And MyClass is defined as :

class MyClass{

  List<Object> fields;
  .
  .
  .
}

Now I am iterating the fields and converting them into proper objects using the code :

public static Class<?> getTypeForObject(Object field) {

    Field returnType = null;
    try {
        returnType = field.getClass().getDeclaredField("type");
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    }
    return returnType.getType();
}

public static Object getValueForObject(Object field) {

    Object obj = null;
    try {
        obj = field.getClass().getDeclaredField("value").get(field);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    }
    return obj;
}

But when I watch the expression field.getClass(), it gives me LinkedHashMap as its class. I am confused why and if it that Object is internally treated as Map what options am I left with if I want to do it with reflection without using an concrete data structures so that everything is generalized.

Upvotes: 5

Views: 11920

Answers (4)

earthmover
earthmover

Reputation: 4525

Just have a look at new updated code :

Object obj = new Object() {
    final String type = "java.lang.Integer";
    final Object value = 6;
};

public void demo(){

    try {
        Field typeField = obj.getClass().getDeclaredField("type");
        typeField.setAccessible(true);
        String type = typeField.get(obj).toString();
        Field valueField = obj.getClass().getDeclaredField("value");
        valueField.setAccessible(true);
        String value = valueField.get(obj).toString();
        Class intClass = Class.forName(type);
        Constructor intCons = intClass.getConstructor(String.class);
        Integer i = (Integer) intCons.newInstance(value.toString());
        System.out.println(i);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Note : got help from this question.

UPDATE: Now getting the type and value from Object obj.

Upvotes: 2

icza
icza

Reputation: 417612

Yes, you can. But since the type of obj is an anonymous class extending java.lang.Object, you can't reference its fields (type and value) directly, only via reflection.

Here's the code how you could do it:

    String type = (String) obj.getClass().getDeclaredField("type").get(obj);
    Object value = obj.getClass().getDeclaredField("value").get(obj);

    // Type can be anything, so in order to instantiate it,
    // we have to assume something. We assume it has a constructor
    // which takes only a String value.
    Object recreated = Class.forName(type).getConstructor(String.class)
            .newInstance(value == null ? null : value.toString());
    System.out.println(recreated);

Upvotes: 8

codeMan
codeMan

Reputation: 5758

Yes, You can use Class.forName.

For example, instead of Integer, consider a Person--

public static String getObjectType()
{
    return "Person";
}

final String type = getObjectType();

Class.forName(type);  //returns the `Person.class`, if Person.class is in classpath if not throws a `ClassNotFoundException`

To create a Person object from the Person.Class you can do something like this -

final Person p = Person.class.getConstructor(Integer.class, String.class).newInstance(age, name);

Upvotes: 1

Bananan
Bananan

Reputation: 609

This will retrieve value of a type field from your object:obj.getClass().getDeclaredField("type").get(obj);.

Upvotes: 1

Related Questions