selectOneMenu with Converter - java.io.NotSerializableException错误

时间:2013-04-17 10:02:53

标签: hibernate jsf jsf-2 primefaces

我有以下JSF表单:

...
<p:column>
    <h:outputText value="Image Id:" style="font-weight:bold; padding-right:10px" />
</p:column>
<p:column>
    <h:outputText value="#{syncCenterBean.selectedCRImageData.imId}" />
</p:column>
</p:row>                    
....                    
<p:row>
<p:column>
    <h:outputText value="Image Type" style="font-weight:bold; padding-right:10px" />
</p:column>
<p:column>
    <p:selectOneMenu id="imtype" value="#{syncCenterBean.cRImageType}" converter="#{imageTypeConvert}">
        <f:selectItem itemLabel="Select One" itemValue="" />
        <f:selectItems value="#{syncCenterBean.cRImageTypeList}" var="cRImageType" itemValue="#{cRImageType.imTypeId}" itemLabel="#{cRImageType.imTypeName}" />
    </p:selectOneMenu>
</p:column>
</p:row>
...

当选择一行数据表时,所有这些都在加载的对话框中。我有两个相关的Hibernate实体如下:

CRImageData

@Entity
@Table(name = "imageviewer_crimagedata")
public class CRImageData implements Serializable  {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    @Column(name = "ImId")
    private Long imId;

    @Column(name = "ImName")
    private String imName;

    @Column(name = "ImTypeId")
    private Long imTypeId;

    @Column(name = "ImPatientId")
    private String imPatientId;

    @Column(name = "ImStatus")
    private String imStatus;

    @Column(name = "imFormat")
    private String imFormat;

    @ManyToOne
    @JoinColumn(name="ImTypeId",insertable=false,updatable=false)
    private CRImageType cRImageType;

和CRImageType

@Entity
@Table(name = "imageviewer_crimagetype")
public class CRImageType implements Serializable   {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    @Column(name = "ImTypeId")
    private Long imTypeId;

    @Column(name = "ImTypeName")
    private String imTypeName;

    @Column(name = "ImTypeDescription")
    private String imTypeDescription;

    @ManyToMany(cascade = {CascadeType.ALL})
    @JoinTable(name="imageviewer_imtype_variable", 
    joinColumns={@JoinColumn(name="ImTypeId")}, 
    inverseJoinColumns={@JoinColumn(name="VarId")})
    private Set<CRVariable> crvariables = new HashSet<CRVariable>();

    @OneToMany(mappedBy="cRImageType")
    private Set<CRImageData> cRImageData;

我为selectOneMenu使用以下转换器:

@ViewScoped
@ManagedBean(name = "imageTypeConvert")
@FacesConverter(forClass=CRImageType.class,value="imageTypeConvert")
public class ImageTypeConvert implements Converter {

    @ManagedProperty(value="#{syncCenterBean}")
    private SyncCenterBean syncCenterBean;
    FacesContext context = FacesContext.getCurrentInstance();
    SyncCenterBean mybean =  (SyncCenterBean) context.getExternalContext().getSessionMap().get("syncCenterBean");

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value{
        Long imTypeId = Long.parseLong(value.trim());   
        List<CRImageType> cRImageTypeList = mybean.getcRImageTypeList();
        for (CRImageType cRImageType:cRImageTypeList) {
            if(cRImageType.getImTypeId().compareTo(imTypeId)==0){
            return cRImageType;
        }
        }
        return null;    
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        System.out.println("!!!!!! (2) Into getAsString");
        return Long.toString(((CRImageType) value).getImTypeId());
    }

    public SyncCenterBean getSyncCenterBean() {
        return syncCenterBean;
    }

    public void setSyncCenterBean(SyncCenterBean syncCenterBean) {
        this.syncCenterBean = syncCenterBean;
    }

}

最后是我的BackBean:

@ManagedBean(name = "syncCenterBean")
@ViewScoped
public class SyncCenterBean implements Serializable {
   @PostConstruct
   public void init(){
          cRImageTypeList = getImageTypesDB();
          cRImageType = new CRImageType();      

          cRImageDataList = populateImageOnlyToDataWarehouseList(getImageDataSOAP());

          cRImageDataListLocal = getImageDataDB();
    }
   ...

但是当我尝试加载数据时,我收到以下错误:

javax.portlet.faces.BridgeException: javax.faces.FacesException:         com.forth.actions.ImageTypeConvert
at com.liferay.faces.bridge.BridgePhaseRenderImpl.execute(BridgePhaseRenderImpl.java:98)
at com.liferay.faces.bridge.BridgeImpl.doFacesRequest(BridgeImpl.java:99)
...
Caused by: java.io.NotSerializableException: com.forth.actions.ImageTypeConvert
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1156)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
at java.util.HashMap.writeObject(HashMap.java:1001)

任何想法我一直在做什么错?

1 个答案:

答案 0 :(得分:4)

查看作用域bean必须是可序列化的,因为它们存储在HTTP会话中,而HTTP会话又可以以序列化形式存储在磁盘文件系统中,而不是作为内存中的普通Java对象引用,或者通过网络传输以共享会话在服务器群集中。

使ImageTypeConvert成为请求范围的bean而不是视图范围的bean,因此不需要序列化:

@RequestScoped
@ManagedBean
public class ImageTypeConvert implements Converter {

让它实现serializable:

@ViewScoped
@ManagedBean
public class ImageTypeConvert implements Converter, Serializable {

顺便提一下,你遇到了一个严重的设计问题:你绝不应该永远不要将FacesContext指定为类的实例变量。这不是线程安全的。将这些contextmybean声明移到方法块内。

另请注意,我删除了@FacesConverter注释,因为如果您将#{imageTypeConvert}用作托管bean,它仍然无法使用。另请注意,我删除了托管bean的name,因为您基本上重复了默认值。