Lazy loading exception when using JSF Converter (collection link)

This is my first post after doing a lot of research on this issue.

This example works under Jboss 7.1 with 3.1 seam (solder + persistence + faces) with seam driven persistence context

I ran into a problem, a classic one, 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 to Entity beans. The goal is to stay 100% OO by reusing the JPA model.

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

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
}

      

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>

      

Bean support (i tried using 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 a converter (heavily 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;
        }
    }
}

      

Note that I put this converter here to avoid searching the net for the seam implementation, but this is the same as using the tag <s:objectConverter/>

instead<f:converter converterId="statutConverter"/>

Any help would be greatly appreciated.

+3


source to share


2 answers


You should be able to access the objects in one transaction. If you are sure you are doing this already, you can try getting the entitymanager by viewing it in context instead of typing it in. I had a simulated problem that was solved this way. You can also initialize the collection in a transaction when you first got your reference to it.



Hibernate.initialize(yourCollection);  

      

+1


source


Take a look at this: selectManyCheckbox LazyInitializationException while checking process



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

on<h:selectManyCheckbox>

+1


source







All Articles