telosys
Blame | Last modification | View Log | RSS feed
package org.objectweb.telosys.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.objectweb.telosys.common.TelosysClassLogger;
import org.objectweb.telosys.common.TelosysException;
import org.objectweb.telosys.common.TelosysRuntimeException;
/**
* @author Laurent GUERIN
*
*/
public class BeanUtil
{
private static final TelosysClassLogger $log = new TelosysClassLogger(BeanUtil.class);
//----------------------------------------------------------------------------------------------
// CONSTANTS
//----------------------------------------------------------------------------------------------
private final static String SHALLOW_COPY_ERR = "BeanUtil.shallowCopy error : " ;
public final static int ALL_METHODS = 1 ;
public final static int CLASS_DECLARED_METHODS = 2 ;
//----------------------------------------------------------------------------------------------
/**
* Checks if the return type of the method is compatible with the given expected type
* @param method
* @param expectedType
* @return
*/
private final static boolean isReturnTypeCompatible ( Method method, Class expectedType ) // v 0.9.9
{
// System.out.println("isReturnTypeCompatible('" + method.getName()+"') ..." );
// System.out.println("expectedType : " + expectedType );
Class c = method.getReturnType();
// System.out.println("getReturnType : " + c );
if ( c != null )
{
if ( expectedType.isAssignableFrom( c ) )
{
// System.out.println("isReturnTypeCompatible('" + method.getName()+"') --> return TRUE" );
return true ;
}
}
// System.out.println("isReturnTypeCompatible('" + method.getName()+"') --> return FALSE" );
return false ;
}
//----------------------------------------------------------------------------------------------
/**
* Returns the getter method "getXxxx" or "isXxxx" for the given attribute name,<br>
* and the given expected return type.
* @param methods
* @param sAttribute
* @param expectedType
* @return
*/
private final static Method getGetterMethod ( Method [] methods, String sAttribute, Class expectedType ) // v 0.9.9
{
for ( int i = 0 ; i < methods.length ; i++ )
{
Method m = methods[i] ;
String s = m.getName();
// System.out.println(" . " + s );
if ( s.equals("get"+sAttribute) )
{
if ( isReturnTypeCompatible(m, expectedType) ) return m;
}
if ( s.equals("is"+sAttribute) )
{
if ( isReturnTypeCompatible(m, expectedType) ) return m;
}
}
return null ;
}
// //----------------------------------------------------------------------------------------------
// /**
// * Returns the getter method "getXxxx" or "isXxxx" for the given attribute name
// * @param methods : methods array where to search the getter method
// * @param sAttribute : attribute name
// * @return
// */
// private final static Method getGetterMethod ( Method [] methods, String sAttribute )
// {
// for ( int i = 0 ; i < methods.length ; i++ )
// {
// Method m = methods[i] ;
// String s = m.getName();
// //System.out.println(" . " + s );
// if ( s.equals("get"+sAttribute) )
// {
// return m ; // getMyAttribute
// }
// if ( s.equals("is"+sAttribute) )
// {
// return m ; // isMyBooleanAttribute
// }
// }
// return null ;
// }
//----------------------------------------------------------------------------------------------
/**
* Shallow copy of a bean to another, attribute by attribute : <br>
* call "setXxxx" with corresponding "getXxxx" or "isXxxx" <br>
* NB: the 2 beans must be instances of the same class
*
* @param orig : the original bean to copy
* @param dest : the destination bean
*/
public final static void shallowCopy ( Object orig, Object dest )
{
shallowCopy ( orig, dest, ALL_METHODS );
}
//----------------------------------------------------------------------------------------------
/**
* Shallow copy of a bean to another, attribute by attribute : <br>
* call "setXxxx" with corresponding "getXxxx" or "isXxxx" <br>
* NB: the 2 beans must be instances of the same class
*
* @param orig : the original bean to copy
* @param dest : the destination bean
* @param iFlag : indicates the introspection level : <br>
* ALL_METHODS : all the public methods including those inherited <br>
* CLASS_DECLARED_METHODS : only the methods declared by the class (without inherited methods)
*/
public final static void shallowCopy ( Object orig, Object dest, int iFlag )
{
if (orig == null) {
throw new TelosysRuntimeException(SHALLOW_COPY_ERR+"origin bean is null");
}
if (dest == null) {
throw new TelosysRuntimeException(SHALLOW_COPY_ERR+"destination bean is null");
}
Class clOrig = orig.getClass();
Class clDest = dest.getClass();
if ( clOrig.getName().equals( clDest.getName() ) != true )
{
throw new TelosysRuntimeException(SHALLOW_COPY_ERR+"different classes");
}
Method [] methods = null ;
if ( iFlag == CLASS_DECLARED_METHODS )
{
// get the methods declared by the class or interface (without inherited methods)
methods = clOrig.getDeclaredMethods();
}
else
{
// get all the public member methods of the class or interface,
// including those inherited from superclasses and superinterfaces
methods = clOrig.getMethods();
}
Method methodInvoked = null ;
Object args [] = { "" };
for ( int i = 0 ; i < methods.length ; i++ )
{
// changes in v 0.9.9
// Method mSetter = methods[i] ;
// String s = mSetter.getName();
Method currentMethod = methods[i] ;
String sCurrentMethodName = currentMethod.getName();
if ( sCurrentMethodName.startsWith("set") )
{
String sAttributeName = sCurrentMethodName.substring(3);
Method mSetter = currentMethod ;
//System.out.println(" --> SETTER = " + mSetter.getName() );
Class[] params = mSetter.getParameterTypes();
if ( params.length == 1 ) // setXxxx with just 1 parameter
{
//Class paramType = params[0].getClass() ;
Class paramType = params[0] ;
Method mGetter = getGetterMethod ( methods, sAttributeName, paramType );
//System.out.println(" --> GETTER = " + mGetter );
if ( mGetter != null && mSetter != null )
{
//--- Try to call getter and setter ( NB : a bad bean can throw any kind of Exception )
try
{
//--- Invoke getXxxxxx or isXxxxxx
methodInvoked = mGetter ;
Object oValue = mGetter.invoke( orig , null); // getXxxxx
//--- Invoke setXxxxxx
methodInvoked = mSetter ;
args[0] = oValue ;
mSetter.invoke( dest, args); // setXxxxx
// } catch (IllegalArgumentException e)
// {
// throw new TelosysRuntimeException(SHALLOW_COPY_ERR + getInvokeErrorMsg(method,e), e);
// } catch (IllegalAccessException e)
// {
// throw new TelosysRuntimeException(SHALLOW_COPY_ERR + getInvokeErrorMsg(method,e), e);
// } catch (InvocationTargetException e)
// {
// throw new TelosysRuntimeException(SHALLOW_COPY_ERR + getInvokeErrorMsg(method,e), e);
} catch (Throwable e)
{
throw new TelosysRuntimeException(SHALLOW_COPY_ERR + getInvokeErrorMsg(methodInvoked,e), e);
}
}
}
}
}
}
//----------------------------------------------------------------------------------------------
private static Method findMethod(Class beanClass, String sMethodName)
{
Method meth = null;
try
{
meth = beanClass.getMethod(sMethodName, null);
} catch (SecurityException e)
{
throw new TelosysRuntimeException("findMethod : security violation ", e);
//return null;
} catch (NoSuchMethodException e)
{
return null; // Not found
}
return meth;
}
//----------------------------------------------------------------------------------------------
private static Object callGetterMethod(Method method, Object oBean)
{
try
{
return method.invoke(oBean, null);
} catch (IllegalArgumentException e)
{
throw new TelosysRuntimeException("callGetterMethod : IllegalArgumentException ", e);
//return null;
} catch (IllegalAccessException e)
{
throw new TelosysRuntimeException("callGetterMethod : IllegalAccessException ", e);
//return null;
} catch (InvocationTargetException e)
{
throw new TelosysRuntimeException("callGetterMethod : InvocationTargetException ", e);
//return null;
}
}
//----------------------------------------------------------------------------------------------
private static String getInvokeErrorMsg(Method method, Throwable t)
{
String s1 = "?" ;
String s2 = "?" ;
if ( method != null )
{
String s3 = "" ;
Class c = method.getDeclaringClass() ;
if ( c != null )
{
s3 = c.getName() + "." ;
}
s1 = s3 + method.getName() ;
}
if ( t != null )
{
s2 = t.getClass().getName() ;
}
return "method " + s1 + " invocation : " + s2 ;
}
//----------------------------------------------------------------------------------------------
/**
* Sets the value of the given bean field using reflection
* @param oBean : the bean instance
* @param sFieldName : the field name
* @param sFieldValue : the value to set (it will be converted to the expected type)
*/
public static void setFieldValue(Object oBean, String sFieldName, String sFieldValue)
{
BeanUtilSubPart1.setFieldValue(oBean, sFieldName, sFieldValue);
}
//----------------------------------------------------------------------------------------------
/**
* Returns the value of the given bean field using reflection
* @param oBean : the bean instance
* @param sFieldName : the field name
* @return : the value found
* @throws TelosysException if the field name is unknown or if arguments are invalid
*/
public static Object getFieldValue(Object oBean, String sFieldName) throws TelosysException
{
if (oBean == null)
{
throw new TelosysException("getFieldValue : bean instance is null ");
}
if (sFieldName == null)
{
throw new TelosysException("getFieldValue : field name is null ");
}
//--- Build the "method field name" (1rst char Upper Case)
String sFieldName2 = sFieldName.trim();
char cFirstChar = sFieldName2.charAt(0);
if (Character.isLowerCase(cFirstChar))
{
String s1 = sFieldName2.substring(0, 1);
String s2 = sFieldName2.substring(1);
sFieldName2 = s1.toUpperCase() + s2;
}
Class beanClass = oBean.getClass();
Method getter = null;
//--- Try to find a "getXxxx" getter method
getter = findMethod(beanClass, "get" + sFieldName2);
if (getter != null)
{
return callGetterMethod(getter, oBean);
}
else
{
//--- Try to find a "isXxxx" getter method
getter = findMethod(beanClass, "is" + sFieldName2);
if (getter != null)
{
// System.out.println("get" + sFieldName2 + " : found ");
return callGetterMethod(getter, oBean);
}
else
{
//--- Unknown field
throw new TelosysException("getFieldValue : no field '" + sFieldName
+ "' in class '" + beanClass.getName()+ "'");
}
}
}
private static String trimNotVoidOrNull(String s)
{
if ( s != null )
{
String s2 = s.trim();
if ( s2.length() > 0)
{
return s2;
}
}
return null ;
}
//----------------------------------------------------------------------------------------------
/**
* Returns the "bean name" from the variable name ( in standard "dot notation" )
* @param sName : the variable name to parse ( 'bean.attribute' )
* @return : the "bean name" part : 'aaa' for 'aaa.bbb', 'aaa' for 'aaa' or null for '.aaa'
*/
public static String getBeanName(String sName)
{
if ( sName == null )
{
return null ;
}
if ( sName.trim().length() == 0 )
{
return null ;
}
int iDotIndex = sName.indexOf('.');
if (iDotIndex > 0)
{
//--- There's at least a "." in the name ( and not at the first position )
String[] tokens = sName.split("\\.");
if (tokens.length == 2) // Exactly 2 parts : "bean.attribute"
{
//--- Return the first part : "bean.attribute" => return "bean"
return trimNotVoidOrNull( tokens[0] );
}
else // More than 2 parts : "aa.bb.cc" or more
{
return null ;
}
}
else
{
if (iDotIndex < 0) // No '.' in the name => return all the name
{
return trimNotVoidOrNull(sName);
}
}
// Other cases : "aaa.bbb.ccc.xxx", "aa", ".aa" => return null
return null ;
}
//----------------------------------------------------------------------------------------------
/**
* @param sName : the variable name to parse ( 'bean.attribute', 'bean', '.attribute' )
* @return : the "attribute name" part ( 'attr' for 'bean.attr' or '.attr' )<br>
* or null for 'bean', 'aa.bb.cc', ''
*/
public static String getAttributeName(String sName)
{
if ( sName == null )
{
return null ;
}
if ( sName.trim().length() == 0 )
{
return null ;
}
String sFieldName = null;
int iDotIndex = sName.indexOf('.');
if (iDotIndex > 0)
{
//--- There's at least a "." in the name ( not at the begining : "bean.attribute" )
String[] tokens = sName.split("\\.");
if (tokens.length == 2) // Exactly 2 parts : "bean.attribute"
{
//--- Return the 2nd part : "bean.attribute" => return "attribute"
sFieldName = tokens[1];
}
else // More than 2 parts : "aa.bb.cc" or more
{
return null ;
}
}
else
{
// No '.' or '.' is at the first position => no bean name
if (iDotIndex == 0) // One '.' at the beginning : ".attribute"
{
//--- Remove the '.' at the first position
sFieldName = sName.substring(1);
}
else // No '.'
{
//--- Take it "as is"
//sFieldName = sName;
return null ;
}
}
return trimNotVoidOrNull(sFieldName);
}
}