Mantis - Quercus
Viewing Issue Advanced Details
2657 major always 05-09-08 14:59 05-29-08 19:29
skleinjung  
ferg  
normal  
closed 3.1.6  
fixed  
none    
none 3.2.0  
0002657: PHP foreach fails when iterating over a Java list: java.lang.InstantiationException
The JavaListAdapter's copy() method is implemented by retrieving the Java class of the underlying list object and calling the newInstance method of that class. This operation fails if the list implementation does not have an accessible no-arg constructor, which is the case for many standard List implementations such as java.util.Collections.UnmodifiableRandomAccessList and java.util.Arrays.ArrayList.
Because the ForeachStatement's execute method uses the Value's copy implementation, attempts to iterate over these list types using foreach fails. The stack trace for this failure is included in the Additional Information section of this report.

I am attaching a war file that illustrates this issue. Deploy it to Resin version 3.1.6 and load it's index.php page to see the error.
com.caucho.quercus.QuercusRuntimeException: java.lang.InstantiationException: java.util.Collections$UnmodifiableRandomAccessList
        at com.caucho.quercus.env.JavaListAdapter.copy(JavaListAdapter.java:255)
        at com.caucho.quercus.program.ForeachStatement.execute(ForeachStatement.java:87)
        at com.caucho.quercus.program.BlockStatement.execute(BlockStatement.java:105)
        at com.caucho.quercus.program.QuercusProgram.execute(QuercusProgram.java:272)
        at com.caucho.quercus.page.InterpretedPage.execute(InterpretedPage.java:70)
        at com.caucho.quercus.page.QuercusPage.executeTop(QuercusPage.java:119)
        at com.caucho.quercus.servlet.ResinQuercusServlet.service(ResinQuercusServlet.java:149)
        at com.caucho.quercus.servlet.QuercusServlet.service(QuercusServlet.java:355)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:91)
        at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:103)
        at com.partslogistics.web.servlet.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:27)
        at com.partslogistics.web.servlet.OpenSessionInViewFilter$$FastClassByCGLIB$$71be6d7d.invoke(<generated>)
        at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
        at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:696)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
        at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:631)
        at com.partslogistics.web.servlet.OpenSessionInViewFilter$$EnhancerByCGLIB$$7e85867f.doFilter(<generated>)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:183)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:138)
        at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
        at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:187)
        at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:266)
        at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:270)
        at com.caucho.server.port.TcpConnection.run(TcpConnection.java:678)
        at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:721)
        at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:643)
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.InstantiationException: java.util.Collections$UnmodifiableRandomAccessList
        at java.lang.Class.newInstance0(Class.java:340)
        at java.lang.Class.newInstance(Class.java:308)
        at com.caucho.quercus.env.JavaListAdapter.copy(JavaListAdapter.java:248)
        ... 28 more
 list-bug.war [^] (891 bytes) 05-09-08 14:59
 JavaListAdapter.class [^] (5,717 bytes) 05-09-08 15:04

Notes
(0003040)
skleinjung   
05-09-08 15:04   
In order to fix this issue, the copy method of JavaListAdapter needs to use a different method of instantiating the copy. One possibility is to simply use a pre-selected list implementation. This is done by replacing line 248 of com.caucho.quercus.env.JavaListAdapter with something like the following:

List list = new java.util.ArrayList();

I am successfully using this as a workaround for my application for the time being. However, I do not have enough information about how Quercus is implemented to know if this is a safe general-purpose solution or not. I am, however, attaching a patched version of the JavaListAdapter class file in case anyone else with this problem wants to try it as well.