0

In C#, I got an utility that cast Datatable into a list of specified model, like this:

Datatable dt = conn.GetDataTable(); 
List<BookModel> result = EntityHelper<BookModel>.GetListModel(dataTable); 

And the GetListModel() method that using generic type goes like this:

public static List<T> GetListModel(DataTable dt)
    {
        List<T> lObject= new List<T>();
        for (int i = 0; i < dt.Rows.Count; i++)
        {
            T obj = new T();
            for (int j = 0; j < dt.Columns.Count; j++)
            {
                int index = IndexOfField( dt.Columns[j].ColumnName );
                if (index != -1)
                {
                    PropertyInfo pi = obj.GetType().GetProperties()[index];
                    Type propType = pi.PropertyType;
                    if (propType.IsGenericType && (propType.GetGenericTypeDefinition() == typeof( Nullable<> )))
                    {
                        propType = propType.GetGenericArguments()[0];
                    }
                    if (propType.IsEnum)
                    {
                        int objectValue = 0;
                        Int32.TryParse( dt.Rows[i][j].ToString(), out objectValue );
                        pi.SetValue( obj, Enum.ToObject( propType, objectValue ), null );
                    }
                    else if (dt.Columns[j].DataType == propType && dt.Rows[i][j] != DBNull.Value)
                    {
                        pi.SetValue( obj, dt.Rows[i][j], null );
                    }
                    else if ((propType.Name.Equals( "Boolean" ) || propType.Name.Equals( "bool" )) && dt.Rows[i][j] != DBNull.Value)
                    {
                        pi.SetValue( obj, Convert.ToBoolean( dt.Rows[i][j] ), null );
                    }
                }
            }

            lObject.Add( obj );
        }
        return lObject;
    }

That is C# story, now back to Java. I'm using JDBC to execute a stored proc and return a ResultSet. But I found that in Java, generic type got its information erased at the runtime so I cannot do something like this:

public static <T> List<T> castObject(ResultSet rs)
{
    T x = new T(); //IMPOSSIBLE ;___;
    Field[] fields = x.getClass().getDeclaredFields();
     for(Field field: fields) 
     { 
         field.setAccessible(true); 
     }
    ....
}

If it's impossible to create an utility like this, then is there anyway to reduce boilerplate code after getting a resulset ? My table got like 30 columns and I do not want to deal with codes like this:

actor.setFirstName(rs.getString("first_name"));
actor.setLastName(rs.getString("last_name"));
...
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
julanove
  • 405
  • 5
  • 19
  • 1
    "salary and the number of companies which prefers Java is sadly higher than C#". Sadly? Don't offend the ones you're asking for help from :P – marstran May 16 '20 at 15:30
  • However ... it is entirely irrelevant to your question and a distraction. I edited it out. so that people can focus on your *actual problem*. – Stephen C May 16 '20 at 15:33

1 Answers1

0

You can instantiate the class by passing a Class instance as a parameter to your method. How you do so depends on the version of Java you are using, but here is an example of Java 9 and later (though earlier versions are similar):

public static <T> List<T> castObject(ResultSet rs, Class<T> clazz) throws NoSuchMethodException,
        IllegalAccessException, InvocationTargetException, InstantiationException {

    Constructor<T> constructor = clazz.getConstructor();
    T t = constructor.newInstance();
    ...
}

To call the method:

List<BookModel> bookModels = castObject(rs, BookModel.class);

Calls to setAccessible can be problematic though. This discussion shows a workaround. How to solve InaccessibleObjectException ("Unable to make {member} accessible: module {A} does not 'opens {package}' to {B}") on Java 9?