Posting generic collection "List<T>" doesnt work

This problem was found in vraptor-3.5.2 and vraptor-3.5.4-SNAPSHOT

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:118)
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:48)
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: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:309)
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)
04/04/2014 10:33:27 org.apache.catalina.core.StandardWrapperValve invoke

This is simple, T is not defined, how will VRaptor know which class it should instantiate?

I would be better if you provide a Interface and a Converter to that interface that, somehow knows which implementation use.

Something like this:

public interface MyNewCustomClass {
}

@Converts(MyNewCustomClass.class)
public class MyNewCustomClassConverter implements TwoWayConverter&lt;MyNewCustomClass&gt; {
   public final MyNewCustomClass convert(String value, Class&lt;? extends MyNewCustomClass&gt; type, ResourceBundle bundle) {
      if (&quot;UseThisClass&quot;.equals(value))
         return new UseThisClass();

      throw new IllegalArgumentException(&quot;Unable to know the correct implementation.&quot;);
   }

   public String convert(MyNewCustomClass o) {
       if (o instanceof UseThisClass)
         return &quot;UseThisClass&quot;;

       return &quot;&quot;;
   }
}

public class UseThisClass implements MyNewCustomClass {
}

// action
@Post
public void removeMany(List&lt;MyNewCustomClass&gt; records) {
// ...
}

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

UserController extends BaseController&lt;User&gt;

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);			
		}
	}