Hi,
I´m just adding this topic since i have seen a solution on hibernate
Property accessors.
I just extended the BasicPropertyAccessor with few methods... like invokeNested...
Mapping and code Code as Follows... Persistent class not included.... Anyone has suggestion how i can enhance this nested property acessor? or if one-one is better ?
Regards,
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.aegis.domain.claim" >
<class name="ClaimRecord" table="TCLMREC" >
<meta attribute="sync-DAO">false</meta>
<composite-id name="id" class="com.aegis.domain.claim.ClaimRecordPk">
<key-property name="claimNo" column="Claim_no" type="string"
length="10" />
<key-property name="timestamp" column="Timestamp" type="timestamp"
length="23" />
</composite-id>
<property name="clmFeatureNo" column="Clm_feature_no" type="string"
not-null="true" length="2" />
<property name="clmActObjId" column="clm_act_obj_id" type="integer"
not-null="true" length="10" />
<component name="claimActivity" class="com.aegis.domain.status.ClaimActivity"
insert="true" update="false" lazy="false" >
<property name="id.refGroupCode" column="Clm_office_cd"
type="string" not-null="true" length="6" access="com.bsi.common.hibernate.NestedPropertyAcessor"/>
<property name="id.dataElementCode" column="Clm_activity_cd"
type="string" update="false" not-null="true" length="4" access="com.bsi.common.hibernate.NestedPropertyAcessor"/>
<property name="description" column="Clm_activity_desc"
type="string" not-null="true" length="30" />
<property name="sourceSystemId" column="Source_system_id"
type="string" not-null="true" length="2" />
</component>
<property name="clmActivityDt" column="Clm_activity_dt" type="date"
not-null="true" length="16" />
<property name="remarksTxt" column="Remarks_txt" type="string"
not-null="true" length="150" />
<property name="useridCd" column="Userid_cd" type="string"
not-null="true" length="8" />
</class>
</hibernate-mapping>
Code:
package com.bsi.common.hibernate;
/**
* permits usage of nested properties for component types.
*/
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.PropertyAccessException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.property.BasicPropertyAccessor;
import org.hibernate.property.Getter;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.Setter;
import org.hibernate.property.BasicPropertyAccessor.BasicGetter;
import org.hibernate.property.BasicPropertyAccessor.BasicSetter;
import org.hibernate.util.ReflectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NestedPropertyAcessor implements PropertyAccessor {
private static final Logger log = LoggerFactory.getLogger(BasicPropertyAccessor.class);
private String targetPropertyName;
public Getter getGetter(Class persistentClass, String propertyName)
throws PropertyNotFoundException {
// Method method = NestedPropertyAcessor.getMethod(persistentClass, propertyName, TypeEnum.MUTATOR);
// Class clazz = method.getDeclaringClass();
return new NestedGetter(persistentClass , propertyName);
}
public Setter getSetter(Class persistentClass, String propertyName)
throws PropertyNotFoundException {
// Method method = NestedPropertyAcessor.getMethod(persistentClass, propertyName, TypeEnum.MUTATOR);
// Class clazz = method.getDeclaringClass();
// String shortPropertyName = NestedPropertyAcessor.getLastMethodName(propertyName);
return new NestedSetter (persistentClass , propertyName);
}
public static final class NestedSetter implements Setter {
private Class clazz;
private final String propertyName;
private NestedSetter(Class clazz, String propertyName) {
this.clazz=clazz;
this.propertyName=propertyName;
}
public Setter getSetter(Class theClass, String propertyName)
throws PropertyNotFoundException {
return createSetter(theClass, propertyName);
}
private static Setter createSetter(Class theClass, String propertyName)
throws PropertyNotFoundException {
NestedSetter result = getSetterOrNull(theClass, propertyName);
if (result==null) {
throw new PropertyNotFoundException(
"Could not find a setter for property " +
propertyName +
" in class " +
theClass.getName()
);
}
return result;
}
private static NestedSetter getSetterOrNull(Class theClass, String propertyName) {
Method method = NestedPropertyAcessor.getMethod(theClass, propertyName, TypeEnum.MUTATOR);
Class clazz = method.getDeclaringClass();
String shortPropertyName = NestedPropertyAcessor.getLastMethodName(propertyName);
if (theClass==Object.class || theClass==null) return null;
// Method method = setterMethod(clazz, shortPropertyName);
if (method!=null) {
if ( !ReflectHelper.isPublic(clazz, method) ) method.setAccessible(true);
return new NestedSetter(theClass, propertyName);
}
else {
NestedSetter setter = getSetterOrNull( theClass, propertyName );
if (setter==null) {
Class[] interfaces = theClass.getInterfaces();
for ( int i=0; setter==null && i<interfaces.length; i++ ) {
setter=getSetterOrNull( interfaces[i], propertyName );
}
}
return setter;
}
}
/**
*
* @param clazz - Any class ...
* @param propertyName - property name to get the mwthods.
* @param accessorType - Acessor or Mutator. (Get/Set methods)
* @return
*/
public static Object invokeNested(Object object , Object[] args, Class clazz , String propertyName , TypeEnum accessorType)
{
Object returnObject = null;
PropertyDescriptor descriptor;
Method met = null;
try {
String [] methods = propertyName.split("\\.");
String accumulator = "";
if (methods.length > 1) {
accumulator += methods[0];
descriptor = new PropertyDescriptor (methods[0] , clazz);
Class innerClass = descriptor.getPropertyType();
//Invoke here to get the inner object hold by the parent class.
met = descriptor.getReadMethod();
returnObject = met.invoke(object, new Object[]{});
String remaining = propertyName.substring(accumulator.length() + 1);
returnObject = invokeNested(returnObject, args , innerClass , remaining , accessorType);
}else {
descriptor = new PropertyDescriptor (propertyName , clazz);
if (accessorType.equals(TypeEnum.ACCESSOR)) {
met= descriptor.getReadMethod();
}else if (accessorType.equals(TypeEnum.MUTATOR)){
met= descriptor.getWriteMethod();
}
returnObject = met.invoke(object, args);
}
} catch (IntrospectionException e) {
throw new PropertyAccessException(
e,
"Introspection excepption occurred while calling the nested property.",
true,
clazz,
propertyName
);
} catch (IllegalArgumentException e) {
e.printStackTrace();
throw new PropertyAccessException(
e,
"IllegalArgumentException exception occurred while calling the nested property.",
true,
clazz,
propertyName
);
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new PropertyAccessException(
e,
"IllegalAccessException exception occurred while calling the nested property.",
true,
clazz,
propertyName
);
} catch (InvocationTargetException e) {
e.printStackTrace();
throw new PropertyAccessException(
e,
"InvocationTargetException exception occurred while calling the nested property.",
true,
clazz,
propertyName
);
}
return returnObject;
}
public void set(Object target, Object value, SessionFactoryImplementor factory)
throws HibernateException {
Method method = null;
try {
// method = NestedPropertyAcessor.getMethod(target.getClass(), propertyName, TypeEnum.MUTATOR);
//FIXME: This need a invoke nested ...
invokeNested( target, new Object[] { value }, target.getClass() , propertyName , TypeEnum.MUTATOR );
}
catch (NullPointerException npe) {
if ( (value==null || method ==null) && method.getParameterTypes()[0].isPrimitive() ) {
throw new PropertyAccessException(
npe,
"Null value was assigned to a property of nested primitive type",
true,
clazz,
propertyName
);
}
else {
throw new PropertyAccessException(
npe,
"NullPointerException occurred while calling",
true,
clazz,
propertyName
);
}
}
catch (IllegalArgumentException iae) {
if ( value==null && method.getParameterTypes()[0].isPrimitive() ) {
throw new PropertyAccessException(
iae,
"Null value was assigned to a property of primitive type",
true,
clazz,
propertyName
);
}
else {
log.error(
"IllegalArgumentException in class: " + clazz.getName() +
", setter method of property: " + propertyName
);
log.error(
"expected type: " +
method.getParameterTypes()[0].getName() +
", actual value: " +
( value==null ? null : value.getClass().getName() )
);
throw new PropertyAccessException(
iae,
"IllegalArgumentException occurred while calling",
true,
clazz,
propertyName
);
}
}
}
public Method getMethod() {
return NestedPropertyAcessor.getMethod(clazz, propertyName, TypeEnum.MUTATOR);
}
public String getMethodName() {
return NestedPropertyAcessor.getMethod(clazz, propertyName, TypeEnum.MUTATOR).getName();
}
Object readResolve() {
return createSetter(clazz, propertyName);
}
public String toString() {
return "BasicSetter(" + clazz.getName() + '.' + propertyName + ')';
}
}
public static String getLastMethodName (String nestedProperty)
{
String [] methods = nestedProperty.split("\\.");
return methods[methods.length -1];
}
public static final class NestedGetter implements Getter {
private Class clazz;
private final transient Method method;
private final String propertyName;
private final String nestedPropertyName;
private NestedGetter(Class clazz, String propertyName) {
this.method=NestedPropertyAcessor.getMethod(clazz, propertyName, TypeEnum.ACCESSOR);
this.clazz=clazz;
this.nestedPropertyName = propertyName;
this.propertyName=NestedPropertyAcessor.getLastMethodName(propertyName);
}
public Object get(Object target) throws HibernateException {
try {
return invokeNested(target, new Object[]{}, clazz, nestedPropertyName, TypeEnum.ACCESSOR);
}
catch (IllegalArgumentException iae) {
log.error(
"IllegalArgumentException in class: " + clazz.getName() +
", getter method of property: " + propertyName
);
throw new PropertyAccessException(
iae,
"IllegalArgumentException occurred calling",
false,
clazz,
propertyName
);
}
}
/**
*
* @param clazz - Any class ...
* @param propertyName - property name to get the mwthods.
* @param accessorType - Acessor or Mutator. (Get/Set methods)
* @return
*/
public static Object invokeNested(Object object , Object[] args, Class clazz , String propertyName , TypeEnum accessorType)
{
Object returnObject = null;
PropertyDescriptor descriptor;
Method met = null;
try {
String [] methods = propertyName.split("\\.");
String accumulator = "";
if (methods.length > 1) {
accumulator += methods[0];
descriptor = new PropertyDescriptor (methods[0] , clazz);
Class innerClass = descriptor.getPropertyType();
//Invoke here to get the inner object hold by the parent class.
met = descriptor.getReadMethod();
returnObject = met.invoke(object, new Object[]{});
String remaining = propertyName.substring(accumulator.length() + 1);
returnObject = invokeNested(returnObject, args , innerClass , remaining , accessorType);
}else {
descriptor = new PropertyDescriptor (propertyName , clazz);
if (accessorType.equals(TypeEnum.ACCESSOR)) {
met= descriptor.getReadMethod();
}else if (accessorType.equals(TypeEnum.MUTATOR)){
met= descriptor.getWriteMethod();
}
returnObject = met.invoke(object, args);
}
} catch (IntrospectionException e) {
throw new PropertyAccessException(
e,
"Introspection excepption occurred while calling the nested property.",
true,
clazz,
propertyName
);
} catch (IllegalArgumentException e) {
e.printStackTrace();
throw new PropertyAccessException(
e,
"IllegalArgumentException exception occurred while calling the nested property.",
true,
clazz,
propertyName
);
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new PropertyAccessException(
e,
"IllegalAccessException exception occurred while calling the nested property.",
true,
clazz,
propertyName
);
} catch (InvocationTargetException e) {
e.printStackTrace();
throw new PropertyAccessException(
e,
"InvocationTargetException exception occurred while calling the nested property.",
true,
clazz,
propertyName
);
}
return returnObject;
}
public Object getForInsert(Object target, Map mergeMap, SessionImplementor session) {
return get( target );
}
public Class getReturnType() {
return method.getReturnType();
}
public Method getMethod() {
return method;
}
public String getMethodName() {
return method.getName();
}
public String toString() {
return "BasicGetter(" + clazz.getName() + '.' + propertyName + ')';
}
Object readResolve() {
return createGetter(clazz, propertyName);
}
}
public static Getter createGetter(Class theClass, String propertyName)
throws PropertyNotFoundException {
NestedGetter result = getGetterOrNull(theClass, propertyName);
if (result==null) {
throw new PropertyNotFoundException(
"Could not find a getter for " +
propertyName +
" in class " +
theClass.getName()
);
}
return result;
}
private static NestedGetter getGetterOrNull(Class theClass, String propertyName) {
Method method1=NestedPropertyAcessor.getMethod(theClass, propertyName, TypeEnum.ACCESSOR);
Class clazz=method1.getDeclaringClass();
String shortPropertyName= NestedPropertyAcessor.getLastMethodName(propertyName);
if (theClass==Object.class || theClass==null) return null;
Method nestedMethod = getterMethod(clazz, shortPropertyName);
if (nestedMethod!=null) {
if ( !ReflectHelper.isPublic(clazz, nestedMethod) ) nestedMethod.setAccessible(true);
return new NestedGetter(clazz, propertyName);
}
else {
NestedGetter getter = getGetterOrNull( clazz.getSuperclass(), shortPropertyName );
if (getter==null) {
Class[] interfaces = theClass.getInterfaces();
for ( int i=0; getter==null && i<interfaces.length; i++ ) {
getter=getGetterOrNull( interfaces[i], shortPropertyName );
}
}
return getter;
}
}
private static Method getterMethod(Class theClass, String propertyName) {
Method[] methods = theClass.getDeclaredMethods();
for (int i=0; i<methods.length; i++) {
// only carry on if the method has no parameters
if ( methods[i].getParameterTypes().length == 0 ) {
String methodName = methods[i].getName();
// try "get"
if ( methodName.startsWith("get") ) {
String testStdMethod = Introspector.decapitalize( methodName.substring(3) );
String testOldMethod = methodName.substring(3);
if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
return methods[i];
}
}
// if not "get", then try "is"
if ( methodName.startsWith("is") ) {
String testStdMethod = Introspector.decapitalize( methodName.substring(2) );
String testOldMethod = methodName.substring(2);
if ( testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName) ) {
return methods[i];
}
}
}
}
return null;
}
/**
*
* @param clazz - Any class ...
* @param propertyName - property name to get the mwthods.
* @param accessorType - Acessor or Mutator. (Get/Set methods)
* @return
*/
public static Method getMethod(Class clazz , String propertyName , TypeEnum accessorType)
{
Method met = null;
PropertyDescriptor descriptor;
try {
String [] methods = propertyName.split("\\.");
String accumulator = "";
if (methods.length > 1) {
accumulator += methods[0];
descriptor = new PropertyDescriptor (methods[0] , clazz);
Class innerClass = descriptor.getPropertyType();
String remaining = propertyName.substring(accumulator.length() + 1);
met = getMethod(innerClass , remaining , accessorType);
}else {
descriptor = new PropertyDescriptor (propertyName , clazz);
if (accessorType.equals(TypeEnum.ACCESSOR))
met= descriptor.getReadMethod();
else if (accessorType.equals(TypeEnum.MUTATOR)){
met= descriptor.getWriteMethod();
}
}
} catch (IntrospectionException e) {
throw new PropertyAccessException(
e,
"Introspection excepption occurred while calling the nested property.",
true,
clazz,
propertyName
);
}
return met;
}
public enum TypeEnum {
ACCESSOR,
MUTATOR;
}
}