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.
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);
Take a look at this: selectManyCheckbox LazyInitializationException on process validation
Try:
<f:attribute name="collectionType" value="java.util.ArrayList" />;
on your <h:selectManyCheckbox>
Related
I am try to develop a web application where I need the Conversation scope to carry on with the same String value in multiple xhtml pages with Primefaces 3.5.
When I begin the conversation with conversation.begin(), it throws null pointer exception with conversation being as null.
I know I can't create a instance of Conversation using 'new'. But I can't figure out where am I going wrong and why is it coming to be null.
Please guide.
Snippet of the xhtml where the bean method is called:
<p:column style="text-align: left" headerText="Deal ID"
width="30">
<p:commandLink value="#{selectedDealBean.getDealID()}"
action="#{SearchBean.action(selectedDealBean.getDealID())}"
process="#this" >
</p:commandLink>
</p:column>
Snippet of bean:
#Named()
#ManagedBean
#ConversationScoped
public class SearchBean implements Serializable {
#Inject
private Conversation conversation;
private DealBean selectedDealBean;
private String selectedID;
private SearchObject searchObj = new SearchObject();
public void start() {
this.conversation.begin();
}
public void end() {
conversation.end();
}
public void submit() {
System.out.println(selectedDealBean);
}
public String action(String selectedID) {
String actionstatus = null;
setSelectedID(selectedID);
actionstatus = "/common/dealDisplay.xhtml?faces-redirect=true" ;
start();
return actionstatus;
}
public String onFinish() {
end();
return "/common/create.xhtml";
}
}
You're mixing annotations. Since you're using CDI you should remove #ManagedBean annotation which is possibly the reason why your injection isn't working.
i have two beans DoctorDetailsBean,PatientDetailsBean ,want to populate a combo box with all doctor names in patientRegistration.xhtml
<h:selectOneMenu value="#{patientDetailsBean.refDr}" style="font-size: medium" >
<f:selectItems value="#{patientDetailsBean.drDetailsbeanList}" var="dr" itemLabel="#{dr.doctorName}" itemValue="#{dr.doctorId}" />
</h:selectOneMenu>
DoctorDetailsBean:
#ManagedBean(name="doctorBean")
#SessionScoped
public class DoctorDetailsBean {
private Long doctorId;
private String doctorName;
private String place;
private Long phoneNumber;
//setters&getters
}
PatientdetailsBean:
# ManagedBean(name= "patientDetailsBean")
#SessionScoped
public class PatientDetailsBean implements Serializable {
private Long patientId;
private String patientName;
private long refDr;
#ManagedProperty (value ="#{doctorBean}")
private DoctorDetailsBean doctorDetailsBean;
private List<Doctor> drList;
private List<DoctorDetailsBean> drDetailsbeanList;
private PatientDAO patientDAO;
private DoctorDAO doctorDAO;
//setters&getters
public PatientDetailsBean() {
}
#PostConstruct
public void init() throws AppException,AppSysException{
drList = new ArrayList<Doctor>();
drList = doctorDAO.getAllDoctors();
drDetailsbeanList = new ArrayList<DoctorDetailsBean>();
for (Doctor doctor : drList) {
DoctorDetailsBean doctorDetailsBean = new DoctorDetailsBean();
doctorDetailsBean.setDoctorId(doctor.getDoctorId());
doctorDetailsBean.setDoctorName(doctor.getDoctorName());
doctorDetailsBean.setPlace(doctor.getPlace());
doctorDetailsBean.setPhoneNumber(doctor.getPhoneNumber());
drDetailsbeanList.add(doctorDetailsBean);
} }
How to solve my problem
Your problem is with type of drDetailsbeanList. List<DoctorDetailsBean> is not correct. Create method which returns List<SelectItem> and use it in xhtml.
I am seeing this strange behavior when using #ManagedProperty. I have 2 beans:
UserManager (SessionScoped)
#ManagedBean
#SessionScoped
public class UserManager extends BaseBean implements Serializable
{
private static final long serialVersionUID = 1861000957282002416L;
private User currentUser;
public String login()
{
// set value of currentUser after authentication
}
public User getCurrentUser() {
return currentUser;
}
public boolean isLoggedIn() {
return getCurrentUser() != null;
}
}
CartBean (ALSO SessionScoped)
...
import javax.faces.bean.ManagedProperty;
...
#ManagedBean
#SessionScoped
public class CartBean extends BaseBean implements Serializable
{
#ManagedProperty(value = "#{userManager.loggedIn}")
private boolean loggedIn;
public void updateCart(Movie selectedMovie)
{
if (!loggedIn) {
return;
}
System.out.println("UPDATE CART REQUEST");
int id = selectedMovie.getMovieID();
if (cart.containsKey(id)) {
cart.remove(id);
}
else {
cart.put(id, selectedMovie);
}
}
public void setLoggedIn(boolean loggedIn) {
this.loggedIn = loggedIn;
}
}
After logging in successfully, the value of loggedIn still remains false.
However, if I change the scope of CartBean to #ViewScoped, the value of loggedIn gets updated and I see the sysout.
As per my understanding and also after reading various articles, one can inject a managed bean or its property only if it is of the same or broader scope. But the "same scope" case does not seem to work in my code. What am I missing here?
I am using:
Mojarra 2.1.16
Spring 3.2
Hibernate 4.1
Tomcat 7.0.37
#ManagedProperty annotation can only provide static injection, which means that the annotated property will get injected when and only when the holding #ManagedBean is instantiated.
When you deploy your application, I believe your CartBean was referenced right at the beginning through things like the View cart button, etc. As a consequence, the injection took place too early and since the bean is #SessionScoped, you will carry the initial false value till the end of time :).
Instead of injecting only the boolean field, you should, instead, inject the whole UserManager bean:
#ManagedBean
#SessionScoped
public class CartBean extends BaseBean implements Serializable {
#ManagedProperty(value = "#{userManager}")
private UserManager userManager;
public void updateCart(Movie selectedMovie) {
if (!userManager.isLoggedIn()) {
return;
}
...
}
}
The solution is using Omnifaces it worked for me each time the value change you will get the new value
#ManagedBean
#ViewScoped
public class CartBean extends BaseBean implements Serializable {
private boolean loggedIn;
public void updateCart(Movie selectedMovie) {
loggedIn=Faces.evaluateExpressionGet("#{userManager.loggedIN}");
if (!userManager.isLoggedIn()) {
return;
}
...
}
}
package no.northcreek.mabjo;
import javax.annotation.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class indexBean {
#ManagedProperty(value="defaultValue")
private String firstName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
So above is a code I expect to create the firstName member variable with a default value of "defaultValue". However the value is null. Why?
Seems that you misunderstood the usage of #ManagedProperty
#ManagedProperty annotation is used to dependency injection (DI) a managed bean into the property of another managed bean.
and note that value should point to an ELxpression , like this : value="#{someBean}"
In your case you should just do the following
private String firstName = "defaultValue";
OR
init the value of firstName in your #PostConstruct
#PostConstruct
public void init() {
firstName = "defaultValue";
}
take a look at this example...
Injecting Managed beans in JSF 2.0
I have this Service bean:
#Stateless
public class BookService
{
#PersistenceContext(unitName="persistentUnit")
protected EntityManager entityManager;
public BookModel find(Long id) {
return entityManager.find(BookModel.class, id);
}
}
And the backing bean for the Facelet page is:
#ManagedBean(name = "bookBean")
#RequestScoped
public class BookBean implements Serializable
{
#EJB
private BookService bookService;
#ManagedProperty(value="#{param.id}")
private Long id;
private DataModel<BookModel> books;
private BookModel currentBook;
#PostConstruct
public void init() {
if (id == null) {
// UPDATE: Retrieve a list of books.
} else {
// UPDATE: id shouldn't be null here.
// Get detail info about a book using the id
currentBook = bookService.find(id);
}
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public BookModel getCurrentBook() {
return currentBook;
}
public void setCurrentBook(BookModel currentBook) {
this.currentBook = currentBook;
}
}
Why is the value of id always returns null even though the URL returned as bookedit.jsf?id=5418 I don't understand this.
Also, I find the EntityManager#find method quite restrictive in that it only accept a primary key value as the second parameter. What if I want to pass a [hashed] value instead of the primary key. How can I do this with the EntityManager#find method?
P.S. I notice the EntityManager#find requirement is the same for both OpenJPA and EclipseLink implementations. Hmm...
I just tried this in one of my managed beans, and it is working. Here's the relevant code, it's basically the same as yours:
#ManagedBean
#RequestScoped
public class TestBean {
#ManagedProperty(value = "#{param.id}")
private Long prop;
#PostConstruct
public void init() {
System.out.println(prop);
// prints 1234 if I go to the url with http://localhost/page.jsf?1234
}
public Long getProp() {
return prop;
}
public void setProp(Long prop) {
this.prop = prop;
}
}
I'm running this on glassfish 3.1.1. The only thought I had is maybe the injected EJB is somehow messing up the request scope in the ManagedBean?