Reputation: 5264
Is there a way to set some field in an entity with only an information for the field column name?
for example:
@Entity
@Table(name = "T_PERSON")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "p_id")
private int id;
@Column(name = "p_name")
private String name;
// getters and setters for id and name
}
So I have p_name
and T_PERSON
as an Input and I want to set some value in it.
I found this and this to get field names using column names, and I could use Reflection
to get the setter method, but Are there any alternatives to reflection?
Upvotes: 3
Views: 10682
Reputation: 2608
Since the method to be called is not known at compile time, as per my understanding, reflection is the only way.
If you are trying to avoid having to use reflection in the invoking code, you can write a wrapper method that internally uses reflection to do the setting and then use that method in the invoking method.
Something like this :
public static <T> Map<String, java.lang.reflect.Method> obtainMapOfColumnNamesAndSetters(Class<T> classType) {
Map<String, java.lang.reflect.Method> result = null;
/*
* Use reflection to iterate over all fields and
* identify ones with annotation and build a map of database column names and fields
* and use the field names to obtain the setter method references and save it in a map and return it as result.
*
* The result map's key is the column name and the value is the method to be set.
*
* Note: Ideally, this map needs to be build only once per class.
*/
return result;
}
public static boolean genericHibernatePropertySetter(Object beanObject, Object parameterObject, String annotationValue,
Map<String, java.lang.reflect.Method> columnAndMethodMap)
{
boolean result = false;
/*
* Use this method to hide the reflection from invoking classes.
*
* Fetch the corresponding 'java.lang.reflect.Method' instance from the map.
* Use the method instance to set the parameter on the bean object.
*
*/
return result; // set to true in the implementation
}
Hope this helps.
Upvotes: 0
Reputation: 9102
I think your best bet would be using reflection only. Hibernate internally too uses reflection to read all the mappings done via annotations. If you want to try out the hibernate internal classes then have a look at the SessionFactory implementation class of Hibernate (org.hibernate.impl.SessionFactoryImpl), it holds map containing class metadata (org.hibernate.metadata.ClassMetadata) for each entity. You already must be having a reference to the singleton SessionFactory in your code.
You can get hold of ClassMeta data with
public ClassMetadata getClassMetadata(Class persistentClass) throws HibernateException
There are few methods in ClassMetaData which could be of your interest.For e.g.,
public void setPropertyValue(Object object, String propertyName, Object value, EntityMode entityMode) throws HibernateException;
EntityMode can be specified as EntityMode.POJO
Also if you have a reference of Configuration object used for initializing hibernate you can query for the table you are interested in as
public Table getTable(String schema, String catalog, String name) {
String key = Table.qualify(catalog, schema, name);
return tables.get(key);
}
and there are methods to get the physical or logical column names
public String getPhysicalColumnName(String logicalName, Table table) throws MappingException
and
public String getLogicalColumnName(String physicalName, Table table) throws MappingException
Upvotes: 4
Reputation: 5125
You could run common SQL update query using method like this:
public int updateSomeParameter(String tableName, String idColumnName, int id,
String parameterColumnName, Object newParameterValue) {
String sql = "UPDATE " + tableName + " SET " + parameterColumnName
+ " = :new_value WHERE " + idColumnName + " = :id";
SQLQuery query = session.createSQLQuery(sql);
query.setInteger("id", id);
query.setParameter("new_value", newParameterValue);
return query.executeUpdate();
}
int updateCout = updateSomeParameter("T_PERSON", "p_id", 50, "p_name", "Some New Name");
But this way is highly unrecommended, especially if table and column names come from user input, because it bocomes SQL injection prone.
Upvotes: 0
Reputation: 590
If you have control over Entity class property name creation then create java property name based on table column name(Apply Rule(s) for eg : Rule 1 - for column p_name as pName).
Apply the rule on user input table column name and identify the entity class property and call the setter method.
If dont have control over Entity class property name then using reflection is the best way.
Upvotes: 0
Reputation: 810
While I generally agree with the comments - I'd use JDBCTemplate or some such thing to accomplish what you're after, you might look into @Transient annotations on a field, or possibly just writing something like:
public void setFieldForColumnName(String columnName, Object value){
Switch(columnName){
case("columnA"):
setColumnA(value);
break;
default:
// ....
break;
}
}
Of course, this relies on a string switch - you'd have to convert to if/then if you don't have the ability to switch on strings.
I reiterate, I don't think this is really the ideal way to manage this, but if you are absolutely married to hibernate, this would be one way to do what you want (I Think)
Upvotes: 0