📄 beanswrapper.java
字号:
* @return the wrapped return value of the method.
* @throws InvocationTargetException if the invoked method threw an exception
* @throws IllegalAccessException if the method can't be invoked due to an
* access restriction.
* @throws TemplateModelException if the return value couldn't be wrapped
* (this can happen if the wrapper has an outer identity or is subclassed,
* and the outer identity or the subclass throws an exception. Plain
* BeansWrapper never throws TemplateModelException).
*/
TemplateModel invokeMethod(Object object, Method method, Object[] args)
throws
InvocationTargetException,
IllegalAccessException,
TemplateModelException
{
Object retval = method.invoke(object, args);
return
method.getReturnType() == Void.TYPE
? TemplateModel.NOTHING
: getOuterIdentity().wrap(retval);
}
/**
* Returns a hash model that represents the so-called class static models.
* Every class static model is itself a hash through which you can call
* static methods on the specified class. To obtain a static model for a
* class, get the element of this hash with the fully qualified class name.
* For example, if you place this hash model inside the root data model
* under name "statics", you can use i.e. <code>statics["java.lang.
* System"]. currentTimeMillis()</code> to call the {@link
* java.lang.System#currentTimeMillis()} method.
* @return a hash model whose keys are fully qualified class names, and
* that returns hash models whose elements are the static models of the
* classes.
*/
public TemplateHashModel getStaticModels()
{
return staticModels;
}
public Object newInstance(Class clazz, List arguments)
throws
TemplateModelException
{
try
{
introspectClass(clazz);
Map classInfo = (Map)classCache.get(clazz);
Object ctors = classInfo.get(CONSTRUCTORS);
if(ctors == null)
{
throw new TemplateModelException("Class " + clazz.getName() +
" has no public constructors.");
}
Constructor ctor = null;
Object[] objargs;
if(ctors instanceof Constructor)
{
ctor = (Constructor)ctors;
objargs = unwrapArguments(arguments, getArgTypes(classInfo, ctor));
}
else if(ctors instanceof MethodMap)
{
MethodMap methodMap = (MethodMap)ctors;
objargs = unwrapArguments(arguments, methodMap.getUnwrapTypes(arguments));
ctor = (Constructor)methodMap.getMostSpecific(objargs);
}
else
{
// Cannot happen
throw new Error();
}
if(objargs != null) {
coerceBigDecimals(ctor, objargs);
}
return ctor.newInstance(objargs);
}
catch (TemplateModelException e)
{
throw e;
}
catch (Exception e)
{
throw new TemplateModelException(
"Could not create instance of class " + clazz.getName(), e);
}
}
void introspectClass(Class clazz)
{
synchronized(classCache)
{
if(!classCache.containsKey(clazz))
{
introspectClassInternal(clazz);
}
}
}
private void introspectClassInternal(Class clazz)
{
String className = clazz.getName();
if(cachedClassNames.contains(className))
{
if(logger.isInfoEnabled())
{
logger.info("Detected a reloaded class [" + className +
"]. Clearing BeansWrapper caches.");
}
// Class reload detected, throw away caches
classCache.clear();
cachedClassNames = new HashSet();
synchronized(this)
{
modelCache.clearCache();
}
staticModels.clearCache();
}
classCache.put(clazz, populateClassMap(clazz));
cachedClassNames.add(className);
}
Map getClassKeyMap(Class clazz)
{
Map map;
synchronized(classCache)
{
map = (Map)classCache.get(clazz);
if(map == null)
{
introspectClassInternal(clazz);
map = (Map)classCache.get(clazz);
}
}
return map;
}
/**
* Returns the number of introspected methods/properties that should
* be available via the TemplateHashModel interface. Affected by the
* {@link #setMethodsShadowItems(boolean)} and {@link
* #setExposureLevel(int)} settings.
*/
int keyCount(Class clazz)
{
Map map = getClassKeyMap(clazz);
int count = map.size();
if (map.containsKey(CONSTRUCTORS))
count--;
if (map.containsKey(GENERIC_GET_KEY))
count--;
if (map.containsKey(ARGTYPES))
count--;
return count;
}
/**
* Returns the Set of names of introspected methods/properties that
* should be available via the TemplateHashModel interface. Affected
* by the {@link #setMethodsShadowItems(boolean)} and {@link
* #setExposureLevel(int)} settings.
*/
Set keySet(Class clazz)
{
Set set = new HashSet(getClassKeyMap(clazz).keySet());
set.remove(CONSTRUCTORS);
set.remove(GENERIC_GET_KEY);
set.remove(ARGTYPES);
return set;
}
/**
* Populates a map with property and method descriptors for a specified
* class. If any property or method descriptors specifies a read method
* that is not accessible, replaces it with appropriate accessible method
* from a superclass or interface.
*/
private Map populateClassMap(Class clazz)
{
// Populate first from bean info
Map map = populateClassMapWithBeanInfo(clazz);
// Next add constructors
try
{
Constructor[] ctors = clazz.getConstructors();
if(ctors.length == 1)
{
Constructor ctor = ctors[0];
map.put(CONSTRUCTORS, ctor);
getArgTypes(map).put(ctor, ctor.getParameterTypes());
}
else if(ctors.length > 1)
{
MethodMap ctorMap = new MethodMap("<init>");
for (int i = 0; i < ctors.length; i++)
{
ctorMap.addConstructor(ctors[i]);
}
map.put(CONSTRUCTORS, ctorMap);
}
}
catch(SecurityException e)
{
logger.warn("Canont discover constructors for class " +
clazz.getName(), e);
}
switch(map.size())
{
case 0:
{
map = Collections12.EMPTY_MAP;
break;
}
case 1:
{
Map.Entry e = (Map.Entry)map.entrySet().iterator().next();
map = Collections12.singletonMap(e.getKey(), e.getValue());
break;
}
}
return map;
}
private Map populateClassMapWithBeanInfo(Class clazz)
{
Map classMap = new HashMap();
Map accessibleMethods = discoverAccessibleMethods(clazz);
Method genericGet = (Method)accessibleMethods.get(MethodSignature.GET_STRING_SIGNATURE);
if(genericGet == null)
{
genericGet = (Method)accessibleMethods.get(MethodSignature.GET_OBJECT_SIGNATURE);
}
if(genericGet != null)
{
classMap.put(GENERIC_GET_KEY, genericGet);
}
if(exposureLevel == EXPOSE_NOTHING)
{
return classMap;
}
try
{
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] pda = beanInfo.getPropertyDescriptors();
MethodDescriptor[] mda = beanInfo.getMethodDescriptors();
for(int i = pda.length - 1; i >= 0; --i) {
PropertyDescriptor pd = pda[i];
if(pd instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor ipd =
(IndexedPropertyDescriptor)pd;
Method readMethod = ipd.getIndexedReadMethod();
Method publicReadMethod = getAccessibleMethod(readMethod,
accessibleMethods);
if(publicReadMethod != null && isSafeMethod(publicReadMethod)) {
try {
if(readMethod != publicReadMethod) {
ipd = new IndexedPropertyDescriptor(
ipd.getName(), ipd.getReadMethod(),
ipd.getWriteMethod(), publicReadMethod,
ipd.getIndexedWriteMethod());
}
classMap.put(ipd.getName(), ipd);
getArgTypes(classMap).put(publicReadMethod,
publicReadMethod.getParameterTypes());
}
catch(IntrospectionException e) {
logger.warn("Couldn't properly perform introspection", e);
}
}
}
else {
Method readMethod = pd.getReadMethod();
Method publicReadMethod = getAccessibleMethod(readMethod, accessibleMethods);
if(publicReadMethod != null && isSafeMethod(publicReadMethod)) {
try {
if(readMethod != publicReadMethod) {
pd = new PropertyDescriptor(pd.getName(),
publicReadMethod, pd.getWriteMethod());
pd.setReadMethod(publicReadMethod);
}
classMap.put(pd.getName(), pd);
}
catch(IntrospectionException e)
{
logger.warn("Couldn't properly perform introspection", e);
}
}
}
}
if(exposureLevel < EXPOSE_PROPERTIES_ONLY)
{
for(int i = mda.length - 1; i >= 0; --i)
{
MethodDescriptor md = mda[i];
Method method = md.getMethod();
Method publicMethod = getAccessibleMethod(method, accessibleMethods);
if(publicMethod != null && isSafeMethod(publicMethod))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -