Java 具有泛型形式Bean类的Spring ClassCastException

Java 具有泛型形式Bean类的Spring ClassCastException,java,spring,generics,Java,Spring,Generics,我试图使用一个泛型类作为Spring表单的支持bean,但当Spring框架试图将对象强制转换为实际类型时,最终会出现ClassCastException 提交表单时,尝试调用SrvRecord对象上的方法时发生以下错误(第105行,用注释标记): 表单Bean: public class RecordBean<T> { private T original; private T modified; public RecordBean() {

我试图使用一个泛型类作为Spring表单的支持bean,但当Spring框架试图将对象强制转换为实际类型时,最终会出现ClassCastException

提交表单时,尝试调用SrvRecord对象上的方法时发生以下错误(第105行,用注释标记):

表单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;
    }

}
公共类RecordBean
{
私人T原件;
私有T修改;
公共记录bean()
{
超级();
}
公共记录bean(T原件)
{
this.original=原件;
修改后的=原件;
}
公共T getOriginal()
{
归还原件;
}
公共文件原件(T原件)
{
this.original=原件;
}
公共T getModified()
{
修改返回值;
}
公共无效设置已修改(T已修改)
{
this.modified=modified;
}
}
控制器方法:

@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());

    // ...
}
@RequestMapping(value=“new”,method=RequestMethod.GET)
公共字符串添加(模型)
{
SrvRecord SrvRecord=getSrvRecord();
RecordBean记录=新的RecordBean(srvRecord);
model.addAttribute(“记录”,记录);
返回“通用/新”;
}
@RequestMapping(value=“new”,method=RequestMethod.POST)
公共字符串添加(模型模型,@modeldattribute(“记录”)RecordBean记录)
{
//调用SrvRecord对象上的方法
doSomething(record.getModified().getZone().getName());//第105行
doSomething(record.getOriginal().getZone().getName());
// ...
}
视图:




任何想法或建议都很好。能够使用通用表单bean将从基线中消除大量不必要的代码

仅供参考,使用的Spring版本是3.0.6.0版本

谢谢,
Beau

你可以试着让你的泛型更具体一些

public class RecordBean<T extends interfaceOrSuperclassOfSrvRecord>
公共类RecordBean

您可以尝试使您的泛型更加具体

public class RecordBean<T extends interfaceOrSuperclassOfSrvRecord>
公共类RecordBean

通过为类实现选中的泛型,即在对象中保留
引用,并在必要时使用显式强制转换,您可以找到bug的来源:

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

}
公共类RecordBean
{
私人课堂;
私人T原件;
私有T修改;
公共记录bean(类clazz)
{
超级();
this.clazz=clazz;
}
公共RecordBean(T原始,类clazz)
{
this.clazz=clazz;
this.original=原件;
修改后的=原件;
}
公共记录bean(T原件)
{
这个(original,(Class)original.getClass());
}
公共T getOriginal()
{
归还原件;
}
公共文件原件(T原件)
{
this.original=clazz.cast(原件);
}
公共T getModified()
{
修改返回值;
}
公共无效设置已修改(T已修改)
{
this.modified=clazz.cast(modified);
}
}

通过为类实现选中的泛型,即在对象中保留
引用,并在必要时使用显式强制转换,您可以找到bug的来源:

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

}
公共类RecordBean
{
私人课堂;
私人T原件;
私有T修改;
公共记录bean(类clazz)
{
超级();
this.clazz=clazz;
}
公共RecordBean(T原始,类clazz)
{
this.clazz=clazz;
this.original=原件;
修改后的=原件;
}
公共记录bean(T原件)
{
这个(original,(Class)original.getClass());
}
公共T getOriginal()
{
归还原件;
}
公共文件原件(T原件)
{
this.original=clazz.cast(原件);
}
公共T getModified()
{
修改返回值;
}
公共无效设置已修改(T已修改)
{
this.modified=clazz.cast(modified);
}
}

您可以在Spring上提交一个bug。问题在于Spring使用反射来确定参数类型,而忽略泛型,因此只是实例化一个没有泛型的普通RecordBean对象。因此,RecordBean中的对象只是作为对象创建的,无法将其强制转换为SrvRecord。唯一的解决办法是不要使用泛型

背景

Spring在内部使用MethodParameter类来读取方法参数。有一个方法叫做

public Class<?> getParameterType()
这段代码不带泛型地读取参数。他们需要打电话来妥善处理

this.method.getGenericParameterTypes()[this.parameterIndex]
后来的方法

 HandlerMethodInvoker.resolveModelAttribute()
调用以通过执行以下操作实例化命令类

 bindObject = BeanUtils.instantiateClass(paramType);

但是paramType的值是“com.test.RecordBean”,而不是预期的“com.test.RecordBean”

您可以在Spring上提交一个bug。问题在于Spring使用反射来确定参数类型,而忽略泛型,因此只是实例化一个没有泛型的普通RecordBean对象。因此,RecordBean中的对象只是作为对象创建的,无法将其强制转换为SrvRecord。唯一的解决办法是不要使用泛型

背景

Spring在内部使用MethodParameter类来读取方法参数。有一个方法叫做

public Class<?> getParameterType()
这段代码不带泛型地读取参数。他们需要打电话来妥善处理

this.method.getGenericParameterTypes()[this.parameterIndex]
后来的方法

 HandlerMethodInvoker.resolveModelAttribute()
调用以通过执行以下操作实例化命令类

 bindObject = BeanUtils.instantiateClass(paramType);

但是paramType的值是“com.test.RecordBean”,而不是预期的“com.test.RecordBean”

同样的问题在这里,我发现的唯一解决方案是为每个控制器创建一个额外的类(FormModelObjectCity),所以我的类如下所示:

public class CityDTO {
    private Long id;
    private String name;

    public CityDTO() {

    }

    public Long getId() {
    return id;
    }

    public void setId(Long id) {
    this.id = id;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

}

form.html,根据替换[]