0

I have a set of SQL queries and a corresponding POJO object with a constructor.

Ex.

Student student = new Student(rs.getString("FNAME"), rs.getString("LNAME"), rs.getString("GRADE")); 

Currently I'm mapping the column in result set to a field manually. I would like to make this generic so I can do something like new Student(rs.getRow()) and then I can map it via some kind of configuration file. There could be N number of fields in select query and order doesn't necessarily match with order defined in the constructor.

I would like to have control over the SQL since it could have lot of joins so I am not sure if an ORM would work here. I strictly want something that could map the resultset columns to a field.

I would like to add annotations in my Student class for mapping

8 Answers 8

2
public class StudentRowMapper implements RowMapper<YourStudentPojo> { @Override public YourStudentPojo mapRow(final ResultSet rs, final int arg1) throws SQLException { final YourStudentPojo item = new YourStudentPojo(); item.setFName(rs.getString("FNAME")); return item; } 

Similar to this FName, you can set the other values in your pojo. No need for constructor. Just if you make changes in Pojo then corresponding changes must be done in this method.

Sign up to request clarification or add additional context in comments.

Comments

1

This does seem like a textbook example of a place to use JPA or a similar ORM technology.

However, if you are set on just doing this with annotations, you can create your own annotations - http://www.mkyong.com/java/java-custom-annotations-example/ is a pretty good tutorial on doing so.

You'd create your own @DatabaseField annotation that you'd annotate the fields of the object with, specifying the corresponding Database field. You'd then, in the constructor, take your class (Class klass = this.getClass()), get the declared fields on it (klass.getDeclaredFields()), and for each of those, look at the declared annotations (field.getDeclaredAnnotations()). For each of those, if they are your custom databasefield annotation, make a note of the mapping. Once you have gone through all fields, you'll have a map of fields to database columns, which you can then go ahead and set using reflection (the Field object you have has a set method on it, you'll call that with "this" (the object being constructed) and the value you got with the result set.

Might be an interesting exercise, but I still think you'd be better off with JPA or one of the lighter weight ORMs like SimpleORM.

Comments

1

You can do with java reflection . For example we will take your sql query is like this.

SELECT FirstName 'FNAME', LastName 'LNAME', Grade 'GRADE' FROM Employee 

So you will get the output as the following

FNAME LNAME GRADE 

John Dan A+ 

Then in your java code you will need to reflection to achieve the rest

Suppose your Student class is like this

public class Student { private String LNAME; private String FNAME; private String GRADE; public String getLNAME() { return LNAME; } public void setLNAME(String lNAME) { LNAME = lNAME; } public String getFNAME() { return FNAME; } public void setFNAME(String fNAME) { FNAME = fNAME; } public String getGRADE() { return GRADE; } public void setGRADE(String gRADE) { GRADE = gRADE; } } 

And you can set the corresponding values in the Student class using the following code.

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; public class Main { public static void main(String[] args) { try { //configuring the columns in the sql statement and class String[] ColumnArray = new String[]{"LNAME","FNAME","GRADE"}; // making a hashmap to emulate the result set of sql HashMap<String, String> rs = new HashMap<String, String>(); rs.put("FNAME", "John"); rs.put("LNAME", "Dan"); rs.put("GRADE", "A+"); //reflection of the Class cls = Class.forName("Student"); Object c = cls.newInstance(); Method[] mtd = cls.getMethods(); for (String column : ColumnArray) { Method method = cls.getMethod("set"+column, String.class); method.invoke(c, new Object[]{rs.get(column)}); } //casting the class to employee Student student = (Student) c; //Printing the output System.out.println(student.getFNAME()); System.out.println(student.getLNAME()); System.out.println(student.getGRADE()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }} 

Please let me know if your facing any issue. Happy to help you.

Comments

0

It's not perfect but look at this:

public class Student { private String name; private Integer age; //etc. public Student() { //default constructor } public Student(final ResultSet rs) throws Exception { ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); for (int i = 1; i < columnCount + 1; i++ ) { String name = rsmd.getColumnName(i); if (Student.getField(name)) { Student.getField(name).set(rs.getString(name)); } } } } 

You should also map field to colum type, in example I used only getString.

Comments

0

If result of your query going to be some domain object like Student (nevermind how many joins in FROM statement) then ORM would work fine and maybe it's good solution. If you are going to extract some complex data structure then you can take a look at some Spring features like RowMapper.

Comments

0

You can make use of GSON serialized object mapping.

refer

Comments

0

Check with HIbernate SQLQuery addScalar() Example here http://www.journaldev.com/3422/hibernate-native-sql-example-addscalar-addentity-addjoin-parameter-example

This will exactly give total result-set as POJO object. You can later iterate through it for data.

Let me know if this helps you.

Comments

0

Assume your STUDENT table is as follows.

__________________________ |STUDENT_ID | AGE | NAME | -------------------------- | | | | | | | | -------------------------- 

Your have to have a control over your SQL query. It's return columns must be renamed according to POJO class's variable names. So the SQL query would be like as follows.

SELECT AGE AS age, NAME AS name from STUDENT; 

Finally, the POJO class's constructor is as follows. It will iterate through all the private variables inside the class, and check whether those columns are available in the ResultSet.

import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.sql.ResultSet; public class Student { private int age; private String name; public int getAge() { return age; } public void setAge( int age ) { this.age = age; } public String getName() { return name; } public void setName( String name ) { this.name = name; } public static void main( String[] args ) { new Student( null ); } public Student( ResultSet rs ) { Field[] allFields = this.getClass().getDeclaredFields(); for ( Field field : allFields ) { if ( Modifier.isPrivate( field.getModifiers() ) ) { String fieldName = field.getName(); String methodName = "set" + fieldName.substring( 0, 1 ).toUpperCase() + fieldName.substring( 1 ); try { Method setterMethod = this.getClass().getMethod( methodName, field.getType() ); setterMethod.invoke( this, rs.getObject( fieldName ) ); } catch ( Exception e ) { e.printStackTrace(); } } } } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.