Session and view scoped beans - Values being overwritten - jsf-2

#SessionScoped
public SessionClass{
// Buyer is a view scoped class
private List<Buyer> sessionObject = new ArrayList<Buyer>();
}
When updating a input field buyer.fname. The list is also updated.
Should I change the Buyer class to session scope also.

This has nothing to do with JSF scopes, but everything with the object oriented nature of Java. Apparently the view scoped Buyer instance represents exactly the same reference as the item in the list of the session scoped bean (it's however beyond me how you coded it like that; it would have been explainable if Buyer is actually a JPA entity).
You should be creating a copy of the Buyer instance instead or detach the entity if it's indeed a JPA entity.

Related

CDI - Sessions Scope - New session scope for each request scope

I have a #SessionScoped CDI bean which is nicely storing information per user session. However I would like to use the same bean but have a new instance of it in say a request scope but once it gets created it remains in the session for that request. So for another request I want it to create a new bean.
Is this possible using CDI?
You'd need a new #RequestScoped bean that creates your existing bean class via the normal new operator (i.e. not injected). You can't simultaneously treat a single bean obtained by the container as request and session scoped.

persisting MVC data to ORM

Java or dotNet world is rich of open source frameworks and libraries. We all like to use Spring and Hibernate almost everywhere.
Everyone agrees that hibernate is a very handy tool.
What Hibernate can do ? well, Basically - Hibernate can track our domain objects changes and persist only modified data to database, that is it.
Basically, That is everything we want. I want to load some records from database, do some modifications to them, and call transaction.commit(), and all modifications get persisted, instantaneously.
That is excelent, right !
But how about web world ? In web applications database session must be closed.
I cannot load some domain objects and wait for user to do modifications through HTTP, and persist those objects after modifications.
We have to use detached objects or DTO. How it works ?
User makes modifications in HTML browser, spring Mvc automatically thransfers those HTML modifiactions to our customized DTO objects using MVC model binding,
then we do some programming effort to transfer modifications from DTO objects to hibernate domain objects and only then we persist them.
For example - we have a web form that updates Customer address, and another form which updates customer details.
We must have two different business layer methods - UpdateAddress() and UpdateDetails(), both methods must accept some kind of DTO,
one represents address information, the other represents details infprmation.
We also have custom logic that transfers data from those 2 DTO to the domain class 'Customer'.
Yes, of course, instead of DTO objects we could reuse our domain classes. But it does not make it simpler.
In both cases we will still have to implement custom logic that transfer modifications to persistent objects,
I cannot persist detached object rightaway, because usually domain classes have lots and lots of properties representing numerous relations, for ex. Customer has - Orders property. When I update customer address I don't want to update its orders.
Is there a beautifull universal way to mapping modifications from mvc model to domain objects without writing a lot of custom code and without risk of overwriting too many fields ?
It's good practice to have a data access layer, which translates into having a repository for each domain object / entity. Furthermore, all repositories share common code so you you naturally have an abstract repository:
public abstract class AbstractRepository<E extends BaseModel> implements Repository<E> {
#PersistenceContext
private EntityManager entityManager;
private Class<E> entityClass;
public AbstractRepository(Class<E> entityClass) {
this.entityClass = entityClass;
}
protected EntityManager getEM() {
return entityManager;
}
protected TypedQuery<E> createQuery(String jpql) {
return createQuery(jpql, entityClass);
}
protected <T> TypedQuery<T> createQuery(String jpql, Class<T> typeClass) {
return getEM().createQuery(jpql, typeClass);
}
#Override
public E merge(E entity) {
return getEM().merge(entity);
}
#Override
public void remove(E entity) {
getEM().remove(entity);
}
#Override
public E findById(long id) {
return getEM().find(entityClass, id);
}
}
It's also good practice to have a service layer where you are to create, update and delete instances of an entity (where you could pass through a DTO to the create and update methods if you so desire).
...
#Inject
private CustomerRepository customerRepository;
public Customer createCustomer(CustomerDto customerDto) {
Customer customer = new Customer();
customer.setEmail(customerDto.getEmail());
...
return customerRepository.merge(customer);
}
public Customer updateCustomerAddress(Customer customer, String address) {
customer.setAddress(address);
return customerRepository.merge(customer);
}
...
So it's up to you how many update methods you want. I would typically group them into common operations such as updating the customer's address, where you would pass the customer Id and the updated address from the front end (probably via ajax) to your controller listening on a specific endpoint. This endpoint is where you would use the repository to find the entity first by Id and then pass it to your service to do the address update for example.
Lastly you need to ensure that the data actually gets persisted, so in Spring you can add the #Transactional annotation either to you Spring MVC controller or to your service that does the persisting. I'm not aware of any best practices around this but I prefer adding it to my controllers so that you're always guaranteed to have a transaction no matter what service you are in.

jsf 2 Session bean created for every request [duplicate]

This question already has an answer here:
#SessionScoped bean looses scope and gets recreated all the time, fields become null
(1 answer)
Closed 6 years ago.
ello
I have 2 Managed beans, one View scoped, the other Session scoped. The View scoped bean is defined as
#ManagedBean
#ViewScoped
public class InvoiceController implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty(value="#{invoiceService}")
private InvoiceService invoiceService;
The session scoped bean as
#ManagedBean
#SessionScoped
public class InvoiceService implements Serializable{
I am using the session scoped bean to hold a flag used to decide if a panel should be rendered, when I run this through the debug I find that every time I call the method on the sesison bean, it is a new instance of the bean and therefore does not retain the value of my flag between requests.
What am I doing wrong?
That can happen if you have imported #SessionScoped from the javax.enterprise.context package instead of from the javax.faces.bean package. The former works on CDI #Named beans only, while the latter works on JSF #ManagedBean beans only.
A JSF #ManagedBean without any valid scope would default to #NoneScoped which means that it's newly constructed on every single EL expression referencing the bean, such as the #ManagedProperty. This explains the symptoms you're seeing.
I had a similar problem. I use a save-method in the view scoped bean that calls a method in the session scoped bean to update some values.
This is what I found out by debugging (excuse my non-Java-guru English):
When first loading the page, the instance number of the injected session bean was for example 111111.
But in the save-method (and all other methods called by an action like a commandButton or action listeners btw), suddenly the session bean was of another instance (say 222222).
Both instances 111111 and 222222 contained the very same values.
All methods I called now were done in the 222222 instance and it changed values in there as I wanted it. But the 111111 instance remained untouched and unchanged.
So 222222 was basically a deep(?) clone of 111111, and not even a copy.
But, after the save-method was done and the page got reloaded, the original 111111 instance was used again in the view scope bean.
The 222222 instance just got thrown to the garbage.
My solution for this problem:
I'm not using the ManagedProperty injection anymore.
Instead I made some helper code to get the session bean wherever I need it (aka in the view scoped bean methods):
public Object getSessionBean(String sessionBeanName)
{
return FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, sessionBeanName);
}
For your example above, the call would be:
InvoiceService invoiceService = (InvoiceService) helper.getSessionBean("invoiceService");
Call it in your methods, do not store it as a field in the view scoped bean.
I hope this somehow helps you fix your problem.

Is there a way to load mutiple ModelDriven models for one action class in Struts2?

Is there a way to load mutiple ModelDriven models for one action class or swtich the model on one action class in struts2?
You can return arbitrary objects through ModelDriven by using ModelDriven<Object>. This is often used in CRUD actions to return either a list of domain objects, or a single domain object.
Alternatively, a model object may be composited from other objects, for example, a UserModel might have both List<User> and User properties, each filled with data when appropriate. The properties don't need to be the same type, though, so a model might have User properties, and a list of Headlines or something.

Exception while lazily loading a collection from entity

I fear that I miss a very basic point, but I'm stuck at the moment, hopefully someone can point my eyes starring to hard at it to the right one...
I try to go through my application setup step by step for make myself clear (hoping people won't get bored before they reach the end of the posting):
I have a session scoped CDI component serving as a handler for a JSF 2.0 view. It holds an entity manager, a list of objects and a special single object:
#Named
#SessionScoped
public class EventHandler implements Serializable {
#PersistenceContext
private EntityManager em;
private List<MyEvent> events;
private MyEvent currentEvent;
...
When the view requests the list for displaying a table, it fills the list by querying the database:
Query query = em.createQuery("select e from MyEvent e");
events = (ArrayList<MyEvent>) query.getResultList();
The view shows this in a data table and provides a link to an action method within the handler:
<h:dataTable value="#{eventHandler.events}" var="_var">
...
<h:commandLink action="#{eventHandler.linkAction(_var)}"> ... </h:commandLink>
The action method stores the reference:
public void setCurrentEvent(MyEvent currentEvent) {
this.currentEvent = currentEvent;
...
Within the entity used in the collection and references above, there'a relationship which gets loaded lazily by default:
#ManyToMany(mappedBy="supportedServices")
public Set<MyEntity> getSupportingEntities() {
...
Now, when being in the detail view and trying to access this relationship by doing:
#{eventHandler.currentEvent.supportingEntities...}
I get a org.hibernate.LazyInitializationException telling me that the session is closed.
Shouldn't the handler be able to load the requested relationship at a later point in the 2nd view, when the handler is session scoped and loaded the references via a query?
Hum, I think this is because the persistenceContext, event if it is a member of a session scoped bean, is not session scoped.
When the view is called the first time, a persistence context is created, the entities(events) are loaded and the datatable is populated. Then the persistence context is flushed, closed and the response is sent to the client. This all happen in the same http request.
But when you then call the details view, another http request is issued, and another persistence context is created, and your reference to "currentEvent" is no more attached to the last persistence context. Hence the LazyInitializationError (the entity must be managed to lazy load).
Solutions could be :
Use an extended persistence context (explained here).
Eager fetch the relation :
#ManyToMany(mappedBy="supportedServices", fetch=FetchType.EAGER)
Merge the detached instance of currentEvent before using it in the details view :
entityManager.merge(currentEvent);

Resources