[
https://issues.apache.org/jira/browse/BEANUTILS-353?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12738264#action_12738264
]
Franklin Phan edited comment on BEANUTILS-353 at 8/3/09 10:44 AM:
------------------------------------------------------------------
I am trying your suggestion from your first comment, and I am seeing an
inconsistency with the workings of this "per-classloader" feature. I have two
instances of Tomcat 5.5.27 running on separate machines (one Linux and one
WinXP). Each Tomcat is set up similarly and runs the same copy of a webapp. Per
your suggestion, I wrote each webapp a *Filter* whose *init* method registers
an implementation of *SqlTimestampConverter* that returns a default of null:
{code:title=EmployeeDirFilter.java|borderStyle=solid}
public class EmployeeDirFilter implements RenderFilter, ActionFilter {
private FilterConfig config;
...
public void init(FilterConfig filterConfig) throws PortletException {
config = filterConfig;
// Register a SqlTimestampConverter that returns a default of NULL
BeanUtilsBean.getInstance().getConvertUtils().register(new
SqlTimestampConverter(null), java.sql.Timestamp.class);
}
}
{code}
Using NetBeans Debugger, I can see that during server startup, the init method
is called for both webapps and a new instance of *BeanUtilsBeans* (containing
the corrected *SqlTimestampConverter*) is stored in the *{{valueByClassLoader}}
Map* in *ContextClassLoaderLocal*. Each converter is mapped by the
*ContextClassLoader* gotten from:
{code:title=org.apache.commons.beanutils.ContextClassLoaderLocal.java get()
method|borderStyle=solid}ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();{code}
So far so good.
Later, when the webapps are called again via a different action, one webapp
retrieves the same *BeanUtilsBeans* from the *{{valueByClassLoader}} Map* while
the other webapp gets a different *ContextClassLoader* and creates a second,
new instance of *BeanUtilsBeans* with all the default Converters via the
*{{ConvertUtilsBean.deregister}}* method and stores it in the
*{{valueByClassLoader}} Map*. This new instance of *BeanUtilsBeans* contains,
of course, the _incorrect_ *SqlTimestampConverter*; and *{{valueByClassLoader}}
Map* now contains _two_ *BeanUtilsBeans*. What's causing this discrepant
behavior in the latter Tomcat/webapp?
In case it matters, here's the *Context* for the two webapps in each Tomcat
(notice that *{{useContextClassLoader}}* is set to *{{false}}*:
{code:title=Context element under
<TOMCAT_HOME>/conf/Catalina/localhost|borderStyle=solid}
<?xml version="1.0" encoding="UTF-8"?>
<!-- For Liferay -->
<Context docBase="${catalina.base}/webapps/liferay523"
reloadable="false" crossContext="true">
<!-- JAAS -->
<Realm
className="org.apache.catalina.realm.JAASRealm"
appName="PortalRealm"
userClassNames="com.liferay.portal.kernel.security.jaas.PortalPrincipal"
roleClassNames="com.liferay.portal.kernel.security.jaas.PortalRole"
debug="99"
useContextClassLoader="false"
/>
</Context>
{code}
was (Author: fphan):
I am trying your suggestion from your first comment, and I am seeing an
inconsistency with the workings of this "per-classloader" feature. I have two
instances of Tomcat 5.5.27 running on separate machines (one Linux and one
WinXP). Each Tomcat is set up similarly and runs the same copy of a webapp. Per
your suggestion, I wrote each webapp a *Filter* whose *init* method registers
an implementation of *SqlTimestampConverter* that returns a default of null:
{code:title=EmployeeDirFilter.java|borderStyle=solid}
public class EmployeeDirFilter implements RenderFilter, ActionFilter {
private FilterConfig config;
...
public void init(FilterConfig filterConfig) throws PortletException {
config = filterConfig;
// Register a SqlTimestampConverter that returns a default of NULL
BeanUtilsBean.getInstance().getConvertUtils().register(new
SqlTimestampConverter(null), java.sql.Timestamp.class);
}
}
{code}
Using NetBeans Debugger, I can see that during server startup, the init method
is called for both webapps and a new instance of *BeanUtilsBeans* (containing
the corrected *SqlTimestampConverter*) is stored in the *{{valueByClassLoader}}
Map* in *ContextClassLoaderLocal*. Each converter is mapped by the
*ContextClassLoader* gotten from:
{code:title=org.apache.commons.beanutils.ContextClassLoaderLocal.java get()
method|borderStyle=solid}ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();{code}
So far so good.
Later, when the webapps are called again via a different action, one webapp
retrieves the same *BeanUtilsBeans* from the *{{valueByClassLoader}} Map* while
the other webapp gets a different *ContextClassLoader* and creates a second,
new instance of *BeanUtilsBeans* with all the default Converters via the
*{{ConvertUtilsBean.deregister}}* method and stores it in the
*{{valueByClassLoader}} Map*. This new instance of *BeanUtilsBeans* contains,
of course, the _incorrect_ *SqlTimestampConverter*; and *{{valueByClassLoader}}
Map* now contains _two_ *BeanUtilsBeans*. What's causing this discrepant
behavior in the latter Tomcat/webapp?
> Unable to call isUseDefault() to check whether a default value will be
> returned
> -------------------------------------------------------------------------------
>
> Key: BEANUTILS-353
> URL: https://issues.apache.org/jira/browse/BEANUTILS-353
> Project: Commons BeanUtils
> Issue Type: Bug
> Components: ConvertUtils & Converters
> Affects Versions: 1.8.0
> Environment: WinXP Pro, JDK 1.6.0_14, Tomcat 5.5.27
> Reporter: Franklin Phan
>
> One can never call isUseDefault() to check on a Converter given the way you
> have ConverterFacade designed and in ConvertUtilsBean:
> {{
> private void register(Class clazz, Converter converter) {
> register(new ConverterFacade(converter), clazz);
> }
> }}
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.