2011-11-16 67 views
-1

我想使用泛型類作爲Spring表單輔助bean,但最終SpringClassException嘗試將對象轉換爲實際類型時出現ClassCastException。Spring ClassCastException與泛型表單Bean類

java.lang.ClassCastException: java.lang.Object cannot be cast to com.[...].portal.entity.SrvRecord 
     at com.[...].portal.controller.SrvController.add(SrvController.java:105) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176) 
     at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436) 
     at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424) 
     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790) 
     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719) 
     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669) 
     at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:585) 
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) 
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) 
     at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) 
     at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390) 
     at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) 
     at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) 
     at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) 
     at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:440) 
     at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230) 
     at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114) 
     at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) 
     at org.mortbay.jetty.Server.handle(Server.java:326) 
     at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) 
     at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943) 
     at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756) 
     at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) 
     at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) 
     at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410) 
     at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) 

Form Bean的:

public class RecordBean<T> 
{ 

    private T original; 
    private T modified; 

    public RecordBean() 
    { 
     super(); 
    } 

    public RecordBean(T original) 
    { 
     this.original = original; 
     this.modified = original; 
    } 

    public T getOriginal() 
    { 
     return original; 
    } 

    public void setOriginal(T original) 
    { 
     this.original = original; 
    } 

    public T getModified() 
    { 
     return modified; 
    } 

    public void setModified(T modified) 
    { 
     this.modified = modified; 
    } 

} 

在提交表單,嘗試呼叫的方法的SrvRecord對象(線105,標有評論)上時,會發生下面的錯誤控制方法:

@RequestMapping(value = "new", method = RequestMethod.GET) 
public String add(Model model) 
{ 
    SrvRecord srvRecord = getSrvRecord(); 

    RecordBean<SrvRecord> record = new RecordBean<SrvRecord>(srvRecord); 
    model.addAttribute("record", record); 

    return "generic/new"; 
} 

@RequestMapping(value = "new", method = RequestMethod.POST) 
public String add(Model model, @ModelAttribute("record") RecordBean<SrvRecord> record) 
{ 
    // Call a method on the SrvRecord object 
    doSomething(record.getModified().getZone().getName()); // line 105 
    doSomething(record.getOriginal().getZone().getName()); 

    // ... 
} 

查看:

<c:url value="/edit" var="formUrl" /> 
<form:form commandName="record" action="${formUrl}"> 
    <form:input type="hidden" path="original.zone" /> 
    <form:input type="hidden" path="original.name" />  
    <!-- ... --> 

    <form:input path="modified.zone" /><br /> 
    <form:input path="modified.name" /><br /> 
    <!-- ... --> 
</form:form> 

任何想法或建議都會很棒。能夠使用通用表單bean將消除來自基線的大量不必要的代碼。

僅供參考,所使用的Spring版本是3.0.6.RELEASE。

感謝, 博

+0

顯然'getSrvRecord()'也是通用的,它返回錯誤的類型......右?哪一行是'SrvController.java:105'? – Saintali

+0

'getSrvRecord )'不是泛型的,並且返回一個SrvRecord對象,第105行在'modify'方法中標註了一條註釋 –

+0

但是棧跟蹤表明第105行位於'SrvController.add'中,也許編譯問題I感覺它很好嘗試重新編譯和再次運行 – Saintali

回答

3

您可以在Spring上提交錯誤。問題在於Spring使用反射來確定參數類型,並且它們忽略泛型,因此只是在沒有泛型的情況下實例化一個普通的RecordBean對象。因此RecordBean中的對象只是創建爲Object,並且無法將其轉換爲SrvRecord。唯一的解決方法是不使用泛型。

背景

彈簧內部使用MethodParameter類讀出方法的參數。有一個叫

public Class<?> getParameterType() 

方法調用:

this.method.getParameterTypes()[this.parameterIndex] 

這段代碼讀出參數,而仿製藥。他們將需要調用此處理得當

this.method.getGenericParameterTypes()[this.parameterIndex] 

後來的方法

HandlerMethodInvoker.resolveModelAttribute() 

被稱爲做

bindObject = BeanUtils.instantiateClass(paramType); 

但paramType的值是「例示命令類com.test.RecordBean「而不是」com.test「。RecordBean < SrvRecord>「,因爲它是預期的

+0

謝謝Peter,這是一個很好的答案。 –

1

你可以嘗試讓你的通用更具體。

public class RecordBean<T extends interfaceOrSuperclassOfSrvRecord> 
+0

非常感謝你的建議,這是一個最好的做法,我已經相應地更新了我的代碼 '公共類RecordBean ' 但我繼續有ClassCastException,如下所示: 'java.lang.ClassCastException:com。[...]。portal.entity.DnsRecord不能轉換爲com。[...]。portal.entity.SrvRecord' –

+0

也許你的DnsRecord和SrvRecord應該實現或擴展一個名爲Record的接口或類。然後你可以做類RecordBean

+0

'SrvRecord'擴展'DnsRecord','DnsRecord'是派生所有其他實體的最低級別的類。爲了清楚起見,'RecordBean'應該被命名爲'DnsRecordBean',並且只會用於擴展'DnsRecord'的對象。無論如何,增加另一個「Record」類似乎不會解決任何問題。 –

1

您可以通過實施檢查泛型類去尋找錯誤的根源,那就是拿在對象Class參考,使用時需要顯式轉換:

public class RecordBean<T> 
{ 
    private Class<T> clazz; 
    private T original; 
    private T modified; 

    public RecordBean(Class<T> clazz) 
    { 
     super(); 
     this.clazz = clazz; 
    } 

    public RecordBean(T original, Class<T> clazz) 
    { 
     this.clazz = clazz; 
     this.original = original; 
     this.modified = original; 
    } 

    public RecordBean(T original) 
    { 
     this(original, (Class<T>) original.getClass()); 
    } 

    public T getOriginal() 
    { 
     return original; 
    } 

    public void setOriginal(T original) 
    { 
     this.original = clazz.cast(original); 
    } 

    public T getModified() 
    { 
     return modified; 
    } 

    public void setModified(T modified) 
    { 
     this.modified = clazz.cast(modified); 
    } 

} 
+0

沒有新的類的運氣..它很適合調試。對象,但是當Spring在提交表單時構造對象時,它似乎總是超類的一個實例(在''的情況下爲'Object',或者在'),我開始懷疑這是否僅僅是Spring的限制 –