caelum / vraptor

Simple Java Web MVC Framework
http://vraptor.org
Other
388 stars 205 forks source link

[BUG] posting generic multiple records "List<T>" doesn't work. #607

Open ebett opened 10 years ago

ebett commented 10 years ago

This problem was found in vraptor-3.5.2 and vraptor-3.5.4-SNAPSHOT. I try with OGNL 2.7.3 and IOGI 1.0.0

I have this method in a abstract controller.

@Post
public void removeMany(List<T> records) {
        if(records!=null && records.size()>0){
            try {

                this.repository.delete(records);
                this.result.use(http()).body("{success:true}");
            } 
            catch (Exception ex) {
                fillLogicErrors("removeMany", ex);
            }
        }
}

Vraptor Exception:

GRAVE: Servlet.service() para servlet default lanzó excepción 
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class 
at br.com.caelum.vraptor.http.ognl.ListNullHandler.instantiate(ListNullHandler.java:49) 
at br.com.caelum.vraptor.http.ognl.ReflectionBasedNullHandler.nullPropertyValue(ReflectionBasedNullHandler.java:59) 
at ognl.ASTProperty.getValueBody(ASTProperty.java:11 
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) 
at ognl.SimpleNode.getValue(SimpleNode.java:236) 
at ognl.ASTChain.setValueBody(ASTChain.java:222) 
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220) 
at ognl.SimpleNode.setValue(SimpleNode.java:279) 
at ognl.Ognl.setValue(Ognl.java:737) 
at ognl.Ognl.setValue(Ognl.java:783) 
at br.com.caelum.vraptor.http.ognl.OgnlFacade.setValue(OgnlFacade.java:100) 
at br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.setProperty(OgnlParametersProvider.java:162) 
at br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.createParameter(OgnlParametersProvider.java:134) 
at br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.getParametersFor(OgnlParametersProvider.java:86) 
at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.getParametersFor(ParametersInstantiatorInterceptor.java:132)
at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:86) 
at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59) 
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) 
at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:4 
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) 
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) 
at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83) 
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) 
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) 
at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69) 
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) 
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) 
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) 
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) 
at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44) 
at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91) 
at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:5 
at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:8 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
at ats.webp.core.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:31) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225) 
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) 
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) 
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:16 
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:9 
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) 
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:11 
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) 
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999) 
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565) 
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309) 
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:90 
at java.lang.Thread.run(Thread.java:662) 
04/04/2014 10:33:27 org.apache.catalina.core.StandardWrapperValve invoke
This message was edited 2 times. Last update was at 06/04/2014 18:47:13

T is defined in the child class that extends BaseController for example:

UserController extends BaseController<User>

The post go to "user/removeMany", so the method is in the UserController. I think that is possible found a way to solve this problem.

I don't want to create a converter for each domain class.

In this example, single generic type parameter works well.

@Post
    public void add(T data) {
        validateEntity(data);
        validator.onErrorUse(page()).forwardTo("/json-resp.ftl");

        try {

            this.repository.insert(data);

            this.result.use(http()).body("{success:true}");
        } 
        catch (Exception ex) {
            fillLogicErrors("add", ex);         
        }
    }   
lucascs commented 10 years ago

Same thing for IOGI:

br.com.caelum.vraptor.http.InvalidParameterException: Exception when trying to instantiate Target(name=records, type=interface java.util.List)
    at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.handleException(VRaptorInstantiator.java:96)
    at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:88)
    at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:81)
    at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.instantiateOrAddError(IogiParametersProvider.java:80)
    at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.instantiateParameters(IogiParametersProvider.java:73)
    at br.com.caelum.vraptor.http.iogi.IogiParametersProvider.getParametersFor(IogiParametersProvider.java:63)
    at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.getParametersFor(ParametersInstantiatorInterceptor.java:132)
    at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:86)
    at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
    at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
    at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)
    at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
    at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
    at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
    at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
    at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44)
    at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91)
    at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)
    at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at ats.webp.core.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:31)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
    at br.com.caelum.iogi.reflection.Target.findRawClassType(Target.java:37)
    at br.com.caelum.iogi.reflection.Target.getClassType(Target.java:29)
    at br.com.caelum.iogi.reflection.Target.toString(Target.java:108)
    at java.lang.String.valueOf(String.java:2826)
    at java.lang.StringBuilder.append(StringBuilder.java:115)
    at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.handleException(VRaptorInstantiator.java:96)
    at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:88)
    at br.com.caelum.iogi.collections.IndexedListInstantiator.instantiate(IndexedListInstantiator.java:34)
    at br.com.caelum.iogi.collections.ListInstantiator.instantiate(ListInstantiator.java:25)
    at br.com.caelum.iogi.collections.ListInstantiator.instantiate(ListInstantiator.java:10)
    at br.com.caelum.vraptor.http.iogi.NullDecorator.instantiate(NullDecorator.java:39)
    at br.com.caelum.iogi.MultiInstantiator.instantiate(MultiInstantiator.java:20)
    at br.com.caelum.vraptor.http.iogi.VRaptorInstantiator.instantiate(VRaptorInstantiator.java:86)
    ... 36 more
ebett commented 10 years ago

Some news for this problem?

lucascs commented 10 years ago

Not yet... It's not an easy fix, because we don't have access to the class that binds T at the point its properties are being set...

So we'd have to change a lot of code to support this case, we have to think more about it... Do you want to start the fix and I'll guide you through the code?

ebett commented 10 years ago

I'll start fix when I have time.

lucascs commented 10 years ago

You don't need permission, you can just click on the Fork button and commit on your fork, then send a Pull Request.

On Thu, Apr 24, 2014 at 6:12 PM, Esteban A. Bett notifications@github.comwrote:

I have found a solution for OGNL in the class "br.com.caelum.vraptor.http.ognl.ListNullHandler" method "instantiate":

Object instance =null; if(type instanceof sun.reflect.generics.reflectiveObjects.TypeVariableImpl){ sun.reflect.generics.reflectiveObjects.TypeVariableImpl tvi = (sun.reflect.generics.reflectiveObjects.TypeVariableImpl)type; Type typeToInstantiate = tvi.getBounds()[0]; instance = new Mirror().on(typeToInstantiate).invoke().constructor().withoutArgs(); } else{ Class<?> typeToInstantiate = (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0]; instance = new Mirror().on(typeToInstantiate).invoke().constructor().withoutArgs(); }

— Reply to this email directly or view it on GitHubhttps://github.com/caelum/vraptor/issues/607#issuecomment-41332912 .

ebett commented 10 years ago

Ok, thank you. The solution was an error. I'll try to find a fix to this problem in ognl or iogi library.

2014-04-24 23:50 GMT-03:00 Lucas Cavalcanti notifications@github.com:

You don't need permission, you can just click on the Fork button and commit on your fork, then send a Pull Request.

On Thu, Apr 24, 2014 at 6:12 PM, Esteban A. Bett notifications@github.comwrote:

I have found a solution for OGNL in the class "br.com.caelum.vraptor.http.ognl.ListNullHandler" method "instantiate":

Object instance =null; if(type instanceof sun.reflect.generics.reflectiveObjects.TypeVariableImpl){ sun.reflect.generics.reflectiveObjects.TypeVariableImpl tvi = (sun.reflect.generics.reflectiveObjects.TypeVariableImpl)type; Type typeToInstantiate = tvi.getBounds()[0]; instance = new Mirror().on(typeToInstantiate).invoke().constructor().withoutArgs(); } else{ Class<?> typeToInstantiate = (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0]; instance = new Mirror().on(typeToInstantiate).invoke().constructor().withoutArgs(); }

— Reply to this email directly or view it on GitHub< https://github.com/caelum/vraptor/issues/607#issuecomment-41332912> .

— Reply to this email directly or view it on GitHubhttps://github.com/caelum/vraptor/issues/607#issuecomment-41354470 .