ryandlf
ryandlf

Reputation: 28555

Set Property on Generic Java Bean

Is this possible? I am creating a an object from a JSON string with this code:

String obj = new Gson().toJson(jsonArray.getJSONObject(i));
String className = getClassName(jsonArray.getJSONObject(i));

Class targetClass = null;
try {
    targetClass = Class.forName(className);
} catch (ClassNotFoundException e) {
                e.printStackTrace();
}

//Create Object
Object data = new Gson().fromJson(obj, targetClass);

I then do some database stuff, get a return key value and I want to set that key on the bean object using its setId() setter, but I don't want to have to cast the specific type of object to the generic object because that would require my repeating the exact same code many times just to cast the object.

key = contactsListDAO.manageDataObj(data, sql, true);
((PhoneNumber) data).setId(key);

Can I use some sort of if statement to check if the object contains an id property and then set the id on the generic object without having to cast?

Upvotes: 0

Views: 3283

Answers (3)

ryandlf
ryandlf

Reputation: 28555

Here is my working code. For some reason I could never find the method using class.getMethod() so I had to loop through an array of methods and match the names to the setId method that I knew existed. From there using invoke was the key to setting the property correctly.

public void setIdOnObject(Object obj, int id, Class<?> targetClass) {
    Method[] methods = targetClass.getMethods();
    for(Method i : methods) {
        if(i.getName().equals("setId")) {
            try {
                i.invoke(obj, id);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }           
    }
}

Upvotes: 1

guy mograbi
guy mograbi

Reputation: 28608

reflection can do that but I think maybe here you should do something else. Write a utility function

public static <T> T fromJson(String json, Class<T> clzz)
{
return (T) new Gson().fromJson(obj, targetClass);
}

and then you can call it like so

PhoneNumber data = fromJson(obj, PhoneNumber.class); 

no more conversion.

EDIT : if using "Object" is a constraint you can use reflection

public void  setIdOnObject(Object obj, Object id)
    {
        try{
         Method m =  obj.getClass().getMethod("setId",id.getClass());
            m.invoke(obj, id );

        }catch(NoSuchMethodException  e){ return false; } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

Here is a working example I have, just copy-paste-run.

import java.lang.reflect.InvocationTargetException;
public class Reflection
{

    public static void main( String[] args )
    {
        MyParent p = new MyParent();
        setParentKey( p, "parentKey" );

        MyObj o = new MyObj();
        setParentKey( o, "myParentKey" );
        setMyKey( o, "myKey" );

        System.out.println( "p = " + p );
        System.out.println( "o = " + o );

    }



    public static void invokeMethod( Object p, Object k, String methodName )
    {
        try
        {
            p.getClass().getMethod( methodName, k.getClass() ).invoke( p, k );
        }
        catch ( NoSuchMethodException e )
        {
            e.printStackTrace();
        }
        catch ( InvocationTargetException e )
        {
            e.printStackTrace();
        }
        catch ( IllegalAccessException e )
        {
            e.printStackTrace();
        }
    }

    public static void setParentKey( Object p, Object k )
    {
           invokeMethod( p,k,"setParentKey" );
    }

    public static void setMyKey( Object p, Object k )
    {
        invokeMethod( p,k,"setMyKey" );
    }

    public static class MyParent
    {
        private Object parentKey;
        public void setParentKey( String k )
        {
            parentKey = k;
        }

        @Override
        public String toString()
        {
            return "MyParent{" +
                           "parentKey=" + parentKey +
                           '}';
        }
    }

    public static class MyObj extends MyParent
    {
        private Object myKey;
        public void setMyKey( String k )
        {
            myKey = k;
        }

        @Override
        public String toString()
        {
            return "MyObj{" +
                           "myKey=" + myKey +
                           "} " + super.toString();
        }
    }
}

And the expected output is :

p = MyParent{parentKey=parentKey}
o = MyObj{myKey=myKey} MyParent{parentKey=myParentKey}

Upvotes: 0

Mark Bramnik
Mark Bramnik

Reputation: 42461

If you have (as you mention) "multiple bean types" and "they all have an id property", why don't you define a common interface for you beans with a setId method?

You'll get your beans and just cast to the interface which will be a safe and object-oriented approach. Is it a viable solution for you?

Upvotes: 0

Related Questions