5

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.

Sourabh
  • 1,253
  • 6
  • 21
  • 39
  • Maybe. But you'd just get `obj.value` for `i`; I mean how do you want to use that instance? – Elliott Frisch Jul 10 '14 at 07:35
  • @Elliott : My basic purpose is that if I have an object like `obj` in the given code, i would first want to get the type like `obj.type` and then use probably `Class.forName.newInstance` to get an instance of Integer then using constructors try to set the `obj.value` in `i` – Sourabh Jul 10 '14 at 07:44
  • I understand, that's how you would create some `i`. Now, what do you do with `i`? Because I suspect you want to then pass `i` to something. Maybe print it? – Elliott Frisch Jul 10 '14 at 07:45
  • Yes I do ... into a function that would use `i`. – Sourabh Jul 10 '14 at 07:46
  • @Sourabh I have updated my code [here](http://stackoverflow.com/a/24671025/2764279) – earthmover Jul 10 '14 at 08:00

4 Answers4

8

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);
icza
  • 389,944
  • 63
  • 907
  • 827
  • The answer you have given is absolutely correct but since bananan posted the some minutes before you I will have to give him the correct answer. :) – Sourabh Jul 10 '14 at 07:56
2

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.

Community
  • 1
  • 1
earthmover
  • 4,395
  • 10
  • 43
  • 74
1

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);
codeMan
  • 5,730
  • 3
  • 27
  • 51
  • But I want be knowing whether its the person class. Infact the Person.class is something my type field from obj will give me and using that return type i will be able to get an instance using the method you suggested. – Sourabh Jul 10 '14 at 07:42
  • yes, you can pass the name of any class as a `type`. Please take a loot at my edited answer. – codeMan Jul 10 '14 at 07:48
1

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

Bananan
  • 613
  • 5
  • 19
  • 1
    this was something I was looking for. Can you tell me the difference between `obj.getClass().getField("type")` and `obj.getClass().getDeclaredField("type")`? and why the latter works and not the former? – Sourabh Jul 10 '14 at 07:49
  • 1
    `getField` searches only for public fields, `getDeclaredField` searches for all kind of fields (public, private, protected, default). – Bananan Jul 10 '14 at 07:52