![JAR search and dependency download from the Maven repository](/logo.png)
net.sf.cuf.model.MixedAccessAdapter Maven / Gradle / Ivy
The newest version!
package net.sf.cuf.model;
import java.lang.reflect.Method;
import java.util.StringTokenizer;
import java.util.Map;
/**
* This Adapter maps aspect names to a get/set method call
* or to a Map get/put call.
* The disadvantege to a MethodAccessAdapter is that isEditable always
* returns true and most checks can't be done during the construction,
* so the MapAccessAdapter is less fail fast than the MethodAccessAdapter.
*/
public class MixedAccessAdapter implements AspectAccessAdapter
{
// the aspect names we use for access, never null
private String[] mAspectNames;
// the getter methods to our aspect, never null, mGetMethods.length==mAspectNames.length
private Method[] mGetMethods;
// the set method of our aspect, may be null if the aspect is not mutable or is a map access
private Method mSetMethod;
// the get method prefix, never null
private String mGetPrefix;
// the set method prefix, never null
private String mSetPrefix;
private static final Class[] NO_PARAMS = new Class [0];
private static final Object[] NO_ARGS = new Object[0];
/**
* Creates a new adapter for a mixed map/reflection-based source. As get/set prefix "get"
* and "set" are used.
* @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
*/
public MixedAccessAdapter(final String pAspectName)
{
this(pAspectName, AspectAdapter.GET, AspectAdapter.SET);
}
/**
* Creates a new adapter for a mixed map/reflection-based source. As get/set prefix "get"
* and "set" are used.
* @param pSourceClass the class expected in the source, may be null
* @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
*/
public MixedAccessAdapter(final Class pSourceClass, final String pAspectName)
{
this(pSourceClass, pAspectName, AspectAdapter.GET, AspectAdapter.SET);
}
/**
* Creates a new adapter for a mixed map/reflection-based source.
* @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
* @param pGetterPrefix the prefix we use for the "getter", must not be null nor empty
* @param pSetterPrefix the prefix we use for the "getter", must not be null nor empty nor the getter prefix
*/
public MixedAccessAdapter( final String pAspectName, final String pGetterPrefix, final String pSetterPrefix)
{
this( null, pAspectName, pGetterPrefix, pSetterPrefix);
}
/**
* Creates a new adapter for a mixed map/reflection-based source.
* @param pSourceClass the class expected in the source, may be null
* @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
* @param pGetterPrefix the prefix we use for the "getter", must not be null nor empty
* @param pSetterPrefix the prefix we use for the "getter", must not be null nor empty nor the getter prefix
*/
public MixedAccessAdapter(final Class pSourceClass, final String pAspectName, final String pGetterPrefix, final String pSetterPrefix)
{
// check the setter and getter name
if (pGetterPrefix==null) throw new IllegalArgumentException("GetterPrefix must not be null");
if (pSetterPrefix==null) throw new IllegalArgumentException("SetterPrefix must not be null");
if (pGetterPrefix.length()==0) throw new IllegalArgumentException("GetterPrefix must not be empty");
if (pSetterPrefix.length()==0) throw new IllegalArgumentException("SetterPrefix must not be empty");
if (pSetterPrefix.equals(pGetterPrefix)) throw new IllegalArgumentException("get and set prefix must differ");
mGetPrefix= pGetterPrefix;
mSetPrefix= pSetterPrefix;
// just extract the attribute strings
StringTokenizer st= new StringTokenizer(pAspectName, AspectAdapter.SEPARATOR);
mGetMethods = new Method[st.countTokens()];
mAspectNames= new String[mGetMethods.length];
for (int i= 0; i< mGetMethods.length; i++ )
{
mAspectNames[i]= st.nextToken();
}
if (pSourceClass!=null && !Map.class.isAssignableFrom( pSourceClass))
{
// check if the first aspect if it corresponds to a valid getter
String getterName= mGetPrefix+
mAspectNames[0].substring(0, 1).toUpperCase()+
mAspectNames[0].substring(1);
try
{
pSourceClass.getMethod(getterName, NO_PARAMS);
}
catch (NoSuchMethodException e)
{
throw new IllegalArgumentException("Class "+pSourceClass+
" does not have a method "+
getterName+"(). "+
"If you want to use late binding you must not provide a source class.");
}
}
}
/**
* Returns always true.
* @return true
*/
public boolean isEditable()
{
return true;
}
/**
* Extract the value from the source.
* @param pSource the source, may be null
* @return null or the value
*/
public Object getValue(final Object pSource)
{
if (pSource==null)
{
return null;
}
/*
* we can't map everything staticly, but must check during a get/set if
* the return type matches the stored Method or not.
*/
Object aspect= pSource;
for (int i = 0; i < mAspectNames.length; i++)
{
String aspectName= mAspectNames[i];
if (aspect==null)
{
return null;
}
else if (aspect instanceof Map)
{
Map source= (Map)aspect;
aspect= source.get(aspectName);
}
else
{
aspect = getAspect(aspect, i, aspectName);
}
}
return aspect;
}
private Object getAspect(Object pAspect, final int pI, final String pAspectName)
{
Class aspectClass= pAspect.getClass();
// check if there is no method or or the known method doesn't match
if ((mGetMethods[pI]==null) ||
!mGetMethods[pI].getDeclaringClass().isAssignableFrom(aspectClass))
{
Method getter;
String getterName= mGetPrefix+
pAspectName.substring(0, 1).toUpperCase()+
pAspectName.substring(1);
try
{
getter = aspectClass.getMethod(getterName, NO_PARAMS);
}
catch (NoSuchMethodException e)
{
throw new IllegalArgumentException("Class "+aspectClass+
" does not have a method "+
getterName+"()");
}
mGetMethods[pI]= getter;
}
// we no have the method object, let's call it
try
{
pAspect= mGetMethods[pI].invoke(pAspect, NO_ARGS);
}
catch (Exception e)
{
throw new IllegalArgumentException(
"While extracting aspect "+pAspectName+
" on object of class "+aspectClass+": "+e.getMessage(), e.getCause());
}
return pAspect;
}
/**
* Sets a value to the source.
* @param pSource the source, never null
* @param pValue the new value, may be null
*/
public void setValue(final Object pSource, final Object pValue)
{
Object aspect= pSource;
Object source= aspect;
for (int i = 0; i < mAspectNames.length; i++)
{
String aspectName= mAspectNames[i];
if (aspect instanceof Map)
{
aspect= ((Map)aspect).get(aspectName);
}
else
{
aspect = getAspect(aspect, i, aspectName);
}
if (i==mAspectNames.length-2)
{
source= aspect;
}
}
// just to be sure that no accidential misuse can happen
//noinspection UnusedAssignment
aspect= null;
// set the value
String lastAspectName = mAspectNames[mAspectNames.length-1];
if (source instanceof Map)
{
((Map)source).put(lastAspectName, pValue);
}
else
{
Class sourceClass = source.getClass();
// check if there is no method or or the known method doesn't match
if ((mSetMethod==null) ||
!mSetMethod.getDeclaringClass().isAssignableFrom(sourceClass))
{
// we must extract a new setter
String setterName = mSetPrefix+
lastAspectName.substring(0, 1).toUpperCase()+
lastAspectName.substring(1);
Class getterReturnClass = mGetMethods[mAspectNames.length - 1].getReturnType();
try
{
mSetMethod = sourceClass.getMethod(setterName, new Class []{getterReturnClass});
}
catch (NoSuchMethodException e)
{
String sb = "Class " + sourceClass.getName() +
" does not have a method " +
setterName +
'(' +
getterReturnClass.getName() +
')';
throw new IllegalArgumentException(sb);
}
}
// we now have the method object, let's call it
try
{
mSetMethod.invoke(source, pValue);
}
catch (Exception e)
{
throw new IllegalArgumentException(
"While setting aspect "+lastAspectName +
" on object of class "+sourceClass +": "+
e.getMessage(), e.getCause());
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy