Mapping a JDBC ResultSet to an object - java

I have a user class that has 16 attributes, things such as firstname, lastname, dob, username, password etc... These are all stored in a MySQL database and when I want to retrieve users I use a ResultSet. I want to map each of the columns back to the user attributes but the way I am doing it seems terribly inefficient.
For example I am doing:
//ResultSet rs;
while(rs.next()) {
String uid = rs.getString("UserId");
String fname = rs.getString("FirstName");
...
...
...
User u = new User(uid,fname,...);
//ArrayList<User> users
users.add(u);
}
i.e I retrieve all the columns and then create user objects by inserting all the column values into the User constructor.
Does anyone know of a faster, neater, way of doing this?

If you don't want to use any JPA provider such as OpenJPA or Hibernate, you can just give Apache DbUtils a try.
http://commons.apache.org/proper/commons-dbutils/examples.html
Then your code will look like this:
QueryRunner run = new QueryRunner(dataSource);
// Use the BeanListHandler implementation to convert all
// ResultSet rows into a List of Person JavaBeans.
ResultSetHandler<List<Person>> h = new BeanListHandler<Person>(Person.class);
// Execute the SQL statement and return the results in a List of
// Person objects generated by the BeanListHandler.
List<Person> persons = run.query("SELECT * FROM Person", h);

No need of storing resultSet values into String and again setting into POJO class. Instead set at the time you are retrieving.
Or best way switch to ORM tools like hibernate instead of JDBC which maps your POJO object direct to database.
But as of now use this:
List<User> users=new ArrayList<User>();
while(rs.next()) {
User user = new User();
user.setUserId(rs.getString("UserId"));
user.setFName(rs.getString("FirstName"));
...
...
...
users.add(user);
}

Let's assume you want to use core Java, w/o any strategic frameworks. If you can guarantee, that field name of an entity will be equal to the column in database, you can use Reflection API (otherwise create annotation and define mapping name there)
By FieldName
/**
Class<T> clazz - a list of object types you want to be fetched
ResultSet resultSet - pointer to your retrieved results
*/
List<Field> fields = Arrays.asList(clazz.getDeclaredFields());
for(Field field: fields) {
field.setAccessible(true);
}
List<T> list = new ArrayList<>();
while(resultSet.next()) {
T dto = clazz.getConstructor().newInstance();
for(Field field: fields) {
String name = field.getName();
try{
String value = resultSet.getString(name);
field.set(dto, field.getType().getConstructor(String.class).newInstance(value));
} catch (Exception e) {
e.printStackTrace();
}
}
list.add(dto);
}
By annotation
#Retention(RetentionPolicy.RUNTIME)
public #interface Col {
String name();
}
DTO:
class SomeClass {
#Col(name = "column_in_db_name")
private String columnInDbName;
public SomeClass() {}
// ..
}
Same, but
while(resultSet.next()) {
T dto = clazz.getConstructor().newInstance();
for(Field field: fields) {
Col col = field.getAnnotation(Col.class);
if(col!=null) {
String name = col.name();
try{
String value = resultSet.getString(name);
field.set(dto, field.getType().getConstructor(String.class).newInstance(value));
} catch (Exception e) {
e.printStackTrace();
}
}
}
list.add(dto);
}
Thoughts
In fact, iterating over all Fields might seem ineffective, so I would store mapping somewhere, rather than iterating each time. However, if our T is a DTO with only purpose of transferring data and won't contain loads of unnecessary fields, that's ok. In the end it's much better than using boilerplate methods all the way.
Hope this helps someone.

Complete solution using #TEH-EMPRAH ideas and Generic casting from Cast Object to Generic Type for returning
import annotations.Column;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.*;
public class ObjectMapper<T> {
private Class clazz;
private Map<String, Field> fields = new HashMap<>();
Map<String, String> errors = new HashMap<>();
public DataMapper(Class clazz) {
this.clazz = clazz;
List<Field> fieldList = Arrays.asList(clazz.getDeclaredFields());
for (Field field : fieldList) {
Column col = field.getAnnotation(Column.class);
if (col != null) {
field.setAccessible(true);
fields.put(col.name(), field);
}
}
}
public T map(Map<String, Object> row) throws SQLException {
try {
T dto = (T) clazz.getConstructor().newInstance();
for (Map.Entry<String, Object> entity : row.entrySet()) {
if (entity.getValue() == null) {
continue; // Don't set DBNULL
}
String column = entity.getKey();
Field field = fields.get(column);
if (field != null) {
field.set(dto, convertInstanceOfObject(entity.getValue()));
}
}
return dto;
} catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
throw new SQLException("Problem with data Mapping. See logs.");
}
}
public List<T> map(List<Map<String, Object>> rows) throws SQLException {
List<T> list = new LinkedList<>();
for (Map<String, Object> row : rows) {
list.add(map(row));
}
return list;
}
private T convertInstanceOfObject(Object o) {
try {
return (T) o;
} catch (ClassCastException e) {
return null;
}
}
}
and then in terms of how it ties in with the database, I have the following:
// connect to database (autocloses)
try (DataConnection conn = ds1.getConnection()) {
// fetch rows
List<Map<String, Object>> rows = conn.nativeSelect("SELECT * FROM products");
// map rows to class
ObjectMapper<Product> objectMapper = new ObjectMapper<>(Product.class);
List<Product> products = objectMapper.map(rows);
// display the rows
System.out.println(rows);
// display it as products
for (Product prod : products) {
System.out.println(prod);
}
} catch (Exception e) {
e.printStackTrace();
}

I would like to hint on q2o. It is a JPA based Java object mapper which helps with many of the tedious SQL and JDBC ResultSet related tasks, but without all the complexity an ORM framework comes with. With its help mapping a ResultSet to an object is as easy as this:
while(rs.next()) {
users.add(Q2Obj.fromResultSet(rs, User.class));
}
More about q2o can be found here.

There are answers recommending to use https://commons.apache.org/proper/commons-dbutils/. The default implementation of row processor i.e org.apache.commons.dbutils.BasicRowProcessor in db-utils 1.7 is not thread safe. So, if you are using org.apache.commons.dbutils.QueryRunner::query method in a multi-threaded environment, you should write your custom row processor. It can be done either by implementing org.apache.commons.dbutils.RowProcessor interface or by extending org.apache.commons.dbutils.BasicRowProcessor class. Sample code given below by extending BasicRowProcessor:
class PersonResultSetHandler extends BasicRowProcessor {
#Override
public <T> List<T> toBeanList(ResultSet rs, Class<? extends T> type)
throws SQLException
{
//Handle the ResultSet and return a List of Person
List<Person> personList = .....
return (List<T>) personList;
}
}
Pass the custom row processor to the appropriate org.apache.commons.dbutils.ResultSetHandler implementation. A BeanListHandler has been used in the below code:
QueryRunner qr = new QueryRunner();
List<Person> personList = qr.query(conn, sqlQuery, new BeanListHandler<Person>(Person.class, new PersonResultSetHandler()));
However, https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc is another alternative with a cleaner API. Although, I am not sure about the thread safety aspects of it.

Thank you ##TEH-EMPRAH. His solution "By FieldName" will be final as:
/**
* Method help to convert SQL request data to your custom DTO Java class object.
* Requirements: fields of your Java class should have Type: String and have the same name as in sql table
*
* #param resultSet - sql-request result
* #param clazz - Your DTO Class for mapping
* #return <T> List <T> - List of converted DTO java class objects
*/
public static <T> List <T> convertSQLResultSetToObject(ResultSet resultSet, Class<T> clazz) throws SQLException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
List<Field> fields = Arrays.asList(clazz.getDeclaredFields());
for(Field field: fields) {
field.setAccessible(true);
}
List<T> list = new ArrayList<>();
while(resultSet.next()) {
T dto = clazz.getConstructor().newInstance();
for(Field field: fields) {
String name = field.getName();
try{
String value = resultSet.getString(name);
field.set(dto, field.getType().getConstructor(String.class).newInstance(value));
} catch (Exception e) {
e.printStackTrace();
}
}
list.add(dto);
}
return list;
}

using DbUtils...
The only problem I had with that lib was that sometimes you have relationships in your bean classes, DBUtils does not map that. It only maps the properties in the class of the bean, if you have other complex properties (refering other beans due to DB relationship) you'd have to create "indirect setters" as I call, which are setters that put values into those complex properties's properties.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.simple.JSONObject;
import com.google.gson.Gson;
public class ObjectMapper {
//generic method to convert JDBC resultSet into respective DTo class
#SuppressWarnings("unchecked")
public static Object mapValue(List<Map<String, Object>> rows,Class<?> className) throws Exception
{
List<Object> response=new ArrayList<>();
Gson gson=new Gson();
for(Map<String, Object> row:rows){
org.json.simple.JSONObject jsonObject = new JSONObject();
jsonObject.putAll(row);
String json=jsonObject.toJSONString();
Object actualObject=gson.fromJson(json, className);
response.add(actualObject);
}
return response;
}
public static void main(String args[]) throws Exception{
List<Map<String, Object>> rows=new ArrayList<Map<String, Object>>();
//Hardcoded data for testing
Map<String, Object> row1=new HashMap<String, Object>();
row1.put("name", "Raja");
row1.put("age", 22);
row1.put("location", "India");
Map<String, Object> row2=new HashMap<String, Object>();
row2.put("name", "Rani");
row2.put("age", 20);
row2.put("location", "India");
rows.add(row1);
rows.add(row2);
#SuppressWarnings("unchecked")
List<Dto> res=(List<Dto>) mapValue(rows, Dto.class);
}
}
public class Dto {
private String name;
private Integer age;
private String location;
//getters and setters
}
Try the above code .This can be used as a generic method to map JDBC result to respective DTO class.

Use Statement Fetch Size , if you are retrieving more number of records. like this.
Statement statement = connection.createStatement();
statement.setFetchSize(1000);
Apart from that i dont see an issue with the way you are doing in terms of performance
In terms of Neat. Always use seperate method delegate to map the resultset to POJO object. which can be reused later in the same class
like
private User mapResultSet(ResultSet rs){
User user = new User();
// Map Results
return user;
}
If you have the same name for both columnName and object's fieldName , you could also write reflection utility to load the records back to POJO. and use MetaData to read the columnNames . but for small scale projects using reflection is not an problem. but as i said before there is nothing wrong with the way you are doing.

Related

How to handle map result(two column results) using mybatis interface not sqlSession

I use Spring boot and Mybatis(interface and mapper.xml) in java web app.
My purpose is to convert result list that contains two columns 'name' and 'count' to a map. The first column should be used as a key and the second column as a value in that map.
I know I should rewrite ResultHandler, while how could it take effect by using interface?
The simplest way to do that is using default interface method to do the conversion:
interfact MyMapper {
#Select("SELECT name, count FROM whatever")
List<Map<String, Object>> findCountsList();
default Map<String, Integer> findCounts() {
Map<String, Integer> result = new HashMap<>;
for(Map<String, Object> entry:findCountsList()) {
result.put(entry.get("name"), ((Number)entry.get("count")).intValue());
}
return result;
}
}
Updated. I have implemented this method by add a Interceptor to handle these case and add plugin in mybatis-config.xml to enable it.
Firstly, create a annotation, then you can handle this case by add annotation, overwrite it and set first column as key and the second column as value.
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
#Inherited
public #interface ResultMap {
String value();
}
Secondly, you should implement a interceptor to handle mybatis resultSet which have #ResultMap annotation
public class ResultMapInterceptor implements Interceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(ResultMapInterceptor.class);
#Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget();
DefaultResultSetHandler defaultResultSetHandler = (DefaultResultSetHandler) target;
Field field = ReflectionUtils.findField(DefaultResultSetHandler.class, "mappedStatement");
ReflectionUtils.makeAccessible(field);
MappedStatement mappedStatement = (MappedStatement) field.get(defaultResultSetHandler);
String className = StringUtils.substringBeforeLast(mappedStatement.getId(), ".");
String methodName = StringUtils.substringAfterLast(mappedStatement.getId(), ".");
Method[] methods = Class.forName(className).getDeclaredMethods();
if (methods == null) {
return invocation.proceed();
}
// get method "mappedStatement"
for (Method method : methods) {
if (methodName.equalsIgnoreCase(method.getName())) {
// get annotation ResultMap, if null, then proceed
ResultMap resultMap = method.getAnnotation(ResultMap.class);
if (resultMap == null) {
return invocation.proceed();
}
// convert result map to specify result
Statement statement = (Statement) invocation.getArgs()[0];
return convert2Map(statement);
}
}
return invocation.proceed();
}
#Override
public Object plugin(Object target) {
if (target instanceof ResultSetHandler) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
#Override
public void setProperties(Properties properties) {
}
private Object convert2Map(Statement statement) throws Throwable{
ResultSet resultSet = statement.getResultSet();
if (resultSet == null) {
return null;
}
List<Object> resultList = new ArrayList(4);
Map<Object, Object> map = new HashMap(8);
while (resultSet.next()) {
if (resultSet.getObject(1) != null) {
map.put(resultSet.getObject(1), resultSet.getObject(2));
}
}
resultList.add(map);
LOGGER.debug("map result from DB, {}", resultList);
return resultList;
}
Then enable this interceptor by add plugins in mybatis-config.xml
</configuration>
<plugins>
<plugin interceptor="com.handler.ResultMapInterceptor"/>
</plugins>
</configuration>
Finally, use this annotation in mybatis dao interface.
#ResultMap("")
Map getCountByAccType(SearchFilter searchFilter);
mapper.xml
<select id="getCountByAccType" resultMap="resultMap">
select
id,
count(ACCOUNTTYPE) count
from table t
</select>

Return different type of object based on condition using Java

I've three queries which is
SELECT NAME FROM EMP WHERE EMPID=100; // THIS RETURNS A STRING
SELECT DEPTID FROM EMP WHERE EMPID=100; // THIS RETURNS AN INT
SELECT EMPID FROM DEPT WHERE DEPTID=101; // THIS RETURNS A LIST
Now I'm trying to write a generic code to return the object, but however I'm able to send only one type i.e. list of object at a high level. Is it possible to send result as it is based on the type?
Here is my code
public Object getObjectFromDB(final String query, final Map<Object, Object> inputMap, JdbcTemplate jdbcTemplate, final Object returnType) throws Exception {
final List<Object> obj = new ArrayList<Object>();
try {
jdbcTemplate.query(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
return con.prepareStatement(query);
}
}, new PreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps) throws SQLException {
}
}, new ResultSetExtractor<Object>() {
#Override
public Object extractData(ResultSet rs) throws SQLException,DataAccessException {
while(rs.next()) {
if(returnType instanceof Integer) {
obj.add(rs.getInt(1));
break;
} else if(returnType instanceof String) {
obj.add(rs.getString(1));
break;
} else if(returnType instanceof List) {
obj.add(rs.getObject(1));
}
}
return obj;
}
});
} catch (Exception e) {
LOG.error(e);
}
return obj;
}
It always returns obj which is a list object even though if I want to trigger first query. Any ideas would be appreciated.
Have you tried writing a generic method? See Generic Methods for more info. This could easily work if you already know the return type you are expecting for any particular set of parameters that you pass to your method.
This post describes how to write a method with generic return type.
One possible function protoype can be :
public static <T> List<T> getObjectFromDB(final String query, final Map<Object, Object> inputMap, JdbcTemplate jdbcTemplate, T returnType){
}
It will always return a List<Object> as you are declaring it here
final List<Object> obj = new ArrayList<Object>();
try to check the first element of obj (as it's a list) and its type.

Java : How to create map using the class attributes?

I am trying to create a map from all the attributes that a class have.My class looks like :
public class MyInventory
{
private int tiers = 80;
private int stearing =135;
private int battery = 46;
}
Now I have collected all the methods that the class has as :
Field[] fields = this.getClass().getDeclaredFields();
Now , I am trying to create a Map out of it where keys are the values of the fields and the values are the name of the fields. Example :
Map<46,battery> ...etc
Is there a way to do it?
The attribute values for the above mentioned class were generated by mapping to properties file and by using spring annotation #ConfigurationProperties. Now I need to create the Map but keys the values of the attributes. I tried to use reflect. However did not find a way to get the value of the fields.
Thanks
You can use Introspector class.
public Map<Object, String> populateMap(final Object o) throws Exception {
Map<Object, String> result = new HashMap<>();
for (PropertyDescriptor pd : Introspector.getBeanInfo(o.getClass()).getPropertyDescriptors()) {
String fieldName = pd.getName();
if("class".equals(fieldName) continue;
Object value = pd.getReadMethod().invoke(o);
result.put(value, fieldName);
}
return result;
}
You can call the above method, passing your class as argument.
MyInventory mi = new MyInventory();
// Sets the properties of mi
mi.setXXX...
// Populates map
populateMap(mi);
Map<Integer, String> map() throws IllegalArgumentException, IllegalAccessException {
Field[] fields = getClass().getDeclaredFields();
Map<Integer,String> map = new HashMap<>();
for (Field field : fields) {
map.put(field.getInt(this), field.getName());
}
return map;
}
Of course it will not map properly if different fields have the same value.
I think, you can have getter method in your class
public class MyInventory
{
private int tiers = 80;
private int stearing =135;
private int battery = 46;
public int getBattery()
{
return battery;
}
//and other getter
}
and then you can populate your map as
map.put(inventory.getBattery(),"battery");
Because, when you have value, which means you know what is the type for which you are populating map.
You can use json parser. For example jackson:
import com.fasterxml.jackson.databind.ObjectMapper;
...
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(mapper.writeValueAsString(fooOject), HashMap.class);

How to be avoid duplicates entries at insert to MongoDB

I just want to be shure when inputting new DBObject to DB that it is really unique and Collection doesn't contain key field duplicates .
Here is how it looks now:
public abstract class AbstractMongoDAO<ID, MODEL> implements GenericDAO<ID, MODEL> {
protected Mongo client;
protected Class<MODEL> model;
protected DBCollection dbCollection;
/**
* Contains model data : unique key name and name of get method
*/
protected KeyField keyField;
#SuppressWarnings("unchecked")
protected AbstractMongoDAO() {
ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
model = (Class<MODEL>) genericSuperclass.getActualTypeArguments()[1];
getKeyField();
}
public void connect() throws UnknownHostException {
client = new MongoClient(Config.getMongoHost(), Integer.parseInt(Config.getMongoPort()));
DB clientDB = client.getDB(Config.getMongoDb());
clientDB.authenticate(Config.getMongoDbUser(), Config.getMongoDbPass().toCharArray());
dbCollection = clientDB.getCollection(getCollectionName(model));
}
public void disconnect() {
if (client != null) {
client.close();
}
}
#Override
public void create(MODEL model) {
Object keyValue = get(model);
try {
ObjectMapper mapper = new ObjectMapper();
String requestAsString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(model);
// check if not presented
BasicDBObject dbObject = new BasicDBObject((String) keyValue, requestAsString);
dbCollection.ensureIndex(dbObject, new BasicDBObject("unique", true));
dbCollection.insert(new BasicDBObject((String) keyValue, requestAsString));
} catch (Throwable e) {
throw new RuntimeException(String.format("Duplicate parameters '%s' : '%s'", keyField.id(), keyValue));
}
}
private Object get(MODEL model) {
Object result = null;
try {
Method m = this.model.getMethod(this.keyField.get());
result = m.invoke(model);
} catch (Exception e) {
throw new RuntimeException(String.format("Couldn't find method by name '%s' at class '%s'", this.keyField.get(), this.model.getName()));
}
return result;
}
/**
* Extract the name of collection that is specified at '#Entity' annotation.
*
* #param clazz is model class object.
* #return the name of collection that is specified.
*/
private String getCollectionName(Class<MODEL> clazz) {
Entity entity = clazz.getAnnotation(Entity.class);
String tableName = entity.value();
if (tableName.equals(Mapper.IGNORED_FIELDNAME)) {
// think about usual logger
tableName = clazz.getName();
}
return tableName;
}
private void getKeyField() {
for (Field field : this.model.getDeclaredFields()) {
if (field.isAnnotationPresent(KeyField.class)) {
keyField = field.getAnnotation(KeyField.class);
break;
}
}
if (keyField == null) {
throw new RuntimeException(String.format("Couldn't find key field at class : '%s'", model.getName()));
}
}
KeyFeld is custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface KeyField {
String id();
String get();
String statusProp() default "ALL";
But I'm not shure that this solution really prove this. I'm newly at Mongo.
Any suggestions?
A uniqueness can be maintained in MonboDb using _id field. If we will not provide the value of this field, MongoDB automatically creates a unique id for that particuler collection.
So, in your case just create a property called _id in java & assign your unique field value here. If duplicated, it will throw an exception.
With Spring Data MongoDB (the question was tagged with spring-data, that's why I suggest it), all you need is that:
// Your types
class YourType {
BigInteger id;
#Indexed(unique = true) String emailAddress;
…
}
interface YourTypeRepository extends CrudRepository<YourType, BigInteger> { }
// Infrastructure setup, if you use Spring as container prefer #EnableMongoRepositories
MongoOperations operations = new MongoTemplate(new MongoClient(), "myDatabase");
MongoRepositoryFactory factory = new MongoRepositoryFactory(operations);
YourTypeRepository repository = factory.getRepository(YourTypeRepository.class);
// Now use it…
YourType first = …; // set email address
YourType second = …; // set same email address
repository.save(first);
repository.save(second); // will throw an exception
The crucial part that's most related to your original question is #Indexed as this will cause the required unique index created when you create the repository.
What you get beyond that is:
no need to manually implement any repository (deleted code does not contain bugs \o/)
automatic object-to-document conversion
automatic index creation
powerful repository abstraction to easily query data by declaring query methods
For more details, check out the reference documentation.

Java - How to Avoid Creating List and Then Copying Into it

I have this general function to populate an ArrayList of objects from a database. The problem is that I'm getting a general ArrayList class back from the DB, and then creating the specific subclass of the ArrayList I need to create, and then copying from the generic ArrayList to my subclass. I want to eliminate that unnecessary step of copying from one array to the other, since the performance won't be great with hundreds of rows. How can I eliminate that step using generics?
So, to use a more specific example, I have a data class like
public class UserData {}
and then a class like
public class UserSet extends ArrayList<UserData>
and I would populate the UserSet object by using a function call like
UserSet s = selectAll("SELECT * FROM users", UserSet.class);
and my general function to query the DB and return a UserSet instance is like this.
public static <T, S extends List<T>> S selectAll(String sql, Class<S> listType, Object...args) throws Exception
{
// t = UserData.class in my example
Class<T> t = (Class<T>)((ParameterizedType)listType.getGenericSuperclass()).getActualTypeArguments()[0];
// From Apache's DBUtils project
QueryRunner run = new QueryRunner();
// AnnotatedDataRowProcessor is my class that just converts a DB row into a data object
ResultSetHandler<List<T>> h = new BeanListHandler<T>(t, new AnnotatedDataRowProcessor());
Connection conn = DB.getConnection();
try
{
// creates the new instance of my specific subclass of ArrayList
S result = listType.newInstance();
// returns the ArrayList which I then copy into result
result.addAll(run.query(conn, sql, h, args));
return result;
}
finally
{
DbUtils.close(conn);
}
}
You can customize your BeanListHandler, something like this:
ResultSetHandler<List<T>> h = new BeanListHandler<T>(t, new AnnotatedDataRowProcessor()) {
#Override
public List<T> handle(ResultSet rs) throws SQLException {
List<T> rows = listType.newInstance();
while (rs.next()) {
rows.add(this.handleRow(rs));
}
return rows;
}
};
You will probably need some casts to make this compile, but this is the general idea.
Then calling run.query(conn, sql, h, args) will directly create the type you're looking for.
I actually had to pass in the Class type into the constructor of AnnotatedDataRowProcessor so I wouldn't break the interface methods in this BeanListHandler.
private Class<?> type;
public <T> AnnotatedDataRowProcessor(Class<T> type)
{
this.type = type;
}
#Override
public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException
{
try
{
List<T> list = (List<T>)this.type.newInstance();
while (rs.next())
{
list.add(toBean(rs,type));
}
return list;
}
catch (IllegalAccessException ex)
{
throw new SQLException(ex.getMessage());
}
catch (InstantiationException ex)
{
throw new SQLException(ex.getMessage());
}
}

Categories

Resources