Lazy loading exception when using JSF Converter (refering to a collection)

∥☆過路亽.° 提交于 2019-12-10 10:18:38

问题


This is my first post after many research on this problem.

This example is running under Jboss 7.1 with seam 3.1 (solder + persistence + faces) with seam managed persistence context

I'm facing a problem, the classical failed to lazily initialize a collection, no session or session was closed: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed when using a converter on Entity beans. The aim is to stay 100% Object oriented, by reusing the JPA model.

in beans.xml, org.jboss.seam.transaction.TransactionInterceptor is activated

Entity beans :

@Entity
public class Member implements Serializable {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String email;

    @Column(name = "phone_number")
    private String phoneNumber;

    @ManyToMany
    private List<Statut> listeStatut = new ArrayList<Statut>();

    // getters, setters, hashcode, equals
}

@Entity
public class Statut implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToMany(mappedBy="listeStatut")
    private List<Member> members = new ArrayList<Member>();

    // getters, setters, hashcode, equals
}

The JSF page :

<h:form>
    <h:selectManyCheckbox id="stat" value="#{memberModif.member.listeStatut}">
        <f:converter converterId="statutConverter"/>
        <f:selectItems value="#{memberModif.statutsPossibles}" var="statut" itemValue="#{statut}" itemLabel="#{statut.name}" />
    </h:selectManyCheckbox>


    <h:commandLink id="register" action="#{memberModif.modifier()}" value="Modifier">
        <f:param name="cid" value="#{javax.enterprise.context.conversation.id}"/>
    </h:commandLink>
</h:form>

The backing bean (I tried with ConversationScoped after SessionScoped --> same problem)

@ConversationScoped
@Named
public class MemberModif implements Serializable {

    private static final long serialVersionUID = -291355942822086126L;

    @Inject
    private Logger log;

    @Inject
    private EntityManager em;

    @Inject Conversation conversation;

    private Member member;

    @SuppressWarnings("unused")
    @PostConstruct
    private void init() {
        if (conversation.isTransient()) {
            conversation.begin();
        }
    }

    public String modifier() {
        em.merge(member);
    }

    public Member getMember() {
        if (member == null) {
            member = em.createQuery("from Member m where m.id=:id",Member.class).setParameter("id", new Long(0)).getSingleResult();
        }
        return member;
    }

    public List<Statut> getStatutsPossibles() {
        return em.createQuery("from Statut", Statut.class).getResultList();
    }
}

And the converter (strongly inspired by seam ObjectConverter) :

@FacesConverter("statutConverter")
public class StatutConverter implements Converter, Serializable {

    final private Map<String, Statut> converterMap = new HashMap<String, Statut>();
    final private Map<Statut, String> reverseConverterMap = new HashMap<Statut, String>();

    @Inject
    private transient Conversation conversation;

    private final transient Logger log = Logger.getLogger(StatutConverter.class);

    private int incrementor = 1;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (this.conversation.isTransient()) {
            log.warn("Conversion attempted without a long running conversation");
        }

        return this.converterMap.get(value);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (this.conversation.isTransient()) {
            log.warn("Conversion attempted without a long running conversation");
        }

        if (this.reverseConverterMap.containsKey(value)) {
            return this.reverseConverterMap.get(value);
        } else {
            final String incrementorStringValue = String.valueOf(this.incrementor++);
            this.converterMap.put(incrementorStringValue, (Statut)value);
            this.reverseConverterMap.put( (Statut)value, incrementorStringValue);
            return incrementorStringValue;
        }
    }
}

Please note that I put this converter here to avoid you searching over the net for the seam implementation, but it is the same as using <s:objectConverter/> tag instead of <f:converter converterId="statutConverter"/>

Any help would be greetly appreciated.


回答1:


You should access the objects in the same transaction. If you are sure you are doing that already, you could try getting the entitymanager by looking it up in the context instead of injecting it. Ive had a simular problem which was resolved that way. You can also initialize the collection in the transaction when you first got your reference to it.

Hibernate.initialize(yourCollection);  



回答2:


Take a look at this: selectManyCheckbox LazyInitializationException on process validation

Try: <f:attribute name="collectionType" value="java.util.ArrayList" />; on your <h:selectManyCheckbox>



来源:https://stackoverflow.com/questions/9886390/lazy-loading-exception-when-using-jsf-converter-refering-to-a-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!