Posting generic collection "List<T>" doesnt work

2 respostas
E

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

2 Respostas

Rafael_Guerreiro

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 ("UseThisClass".equals(value))
         return new UseThisClass();

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

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

       return "";
   }
}

public class UseThisClass implements MyNewCustomClass {
}

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

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);			
		}
	}
Criado 4 de abril de 2014
Ultima resposta 4 de abr. de 2014
Respostas 2
Participantes 2