I have a class called Customer and another called Person. The class Customer has a property Person, see the code bellow;
public class Customer{
private String name;
private Person person;
}
But when I try to use the #{customerManagedBean.customer.person.id} I got a error because I can't reach the property id from person, because person is null.
So I changed my code to:
public Class Customer{
public Customer{
person = new Person();
}
private String name;
private Person person;
}
And everything works fine. Is it mandatory initialize all objects inside my class before using it?
Yes, it is. The setter method is only invoked on the final property, which is id. JSF, or more specifically, EL, won't autocreate nested properties for you. The model (the backing bean) is responsible for that. You should in fact create Person in CustomerManagedBean class, not in Customer class.
That it works for managed beans is simply because those managed beans are via #ManagedBean or #Named explicitly registered to be auto-created when they do not exist in the EL scope yet. This does in turn not apply to their nested properties.
Yes.
Initialize the Person instance along with Customer instance in CustomerManagedBean's Constructor or #PostConstruct methods
Related
I have a class that looks like this:
#Named
public class TableView {
#PersistenceContext protected EntityManager em;
#Resource protected UserTransaction utx;
And of course I can get an instance during the construction of my bean like this:
#Inject private TableView view;
I believe it is CDI that has the job of filling in the EntityManager and the UserTransaction. However, after my user class has been instantiated I sometimes want another instance of TableView so how do I get it? Obviously
TableView anotherView = new TableView();
won't work since em and utx will be null. So how do I get a new working instance with the injections performed?
Instance interface should do what you need:
Instance<TableView> tableViewInstance;
TableView anotherView = tableViewInstance.get();
But as stated in the comments, your view should not have/be aware of transactions and entity manager.
I am trying to construct a test website that display various information about a student with JSF 2.0, EJB 3.1 and JPA 2.0.
After a student login, the student can browse different pages for displaying different kind of information, which is what a usual registration management system does. Say displaying a timetable according to enrollment information in one page, and display the assignments in another page. Information that will be displayed include attributes of the student, mapped entities like registered course, assignment submitted etc.
At first, I tried to create a stateless bean and get the information required for each page, and change some attributes of student
#Entity
public class Student{
#Id
private String sid;
private String address;
#ManyToMany
private List<Assignment> submittedAssignments;
#ManyToMany
private List<Course> courses;
}
#Stateless
#LocalBean
public class studentDao {
#PersistenceContext(unitName="PU")
private EntityManager em;
public Student getStudent(String sid){
return em.find(Student.class, sid);
}
public List<Course> getCoursesByStudent(String sid){
return em.find(Student.class, sid).getCourses();
}
public List<Assignment> getAssignmentsByStudent(String sid){
return em.find(Student.class, sid).getSubmittedAssignments();
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void ChangeAddress(String sid, String newAddress){
em.find(Student.class, sid).setAddress(newAddress);
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void SubmitAssignment(String sid, Assignment submittedAssignment){
}
//Some more methods, just list a few for illustration.
}
#ManagedBean
#SessionScoped
public class LoginSession{
private String sid;
//getter
public login(String sid){
//probably will need password validation later, so I have to connect to db and check the password.
this.sid=sid;
}
}
#ManagedBean
#RequestScoped
public class AssignmentBean{
#EJB
private StudentDao studentDao;
#ManagedProperty(value="#{loginSession}")
private LoginSession session;
public List<Assignment> getAssignments(){
return studentDao.getAssignmentsByStudent(session.sid);
}
}
assignment.xhtml:
<h:datatable value="#{assignmentBean.assignments}"></h:datatable>
And then, I find it quite tedious to pass student from managed bean to stateless ejb, retrieve student, again and again, then return only a part of information to ManagedBean for display, therefore I think I can do it like this.
#Stateful
#LocalBean
public class studentDao {
#PersistenceContext(unitName="PU", type=PersistenceContextType.EXTENDED)
private EntityManager em;
private Student currentStudent;
public void login(String sid){
//didn't make a password, just type sid and done.
currentStudent = em.find(Student.class, sid);
}
public Boolean getLoggedIn(){
return currentStudent != null;
}
public Student getCurrentStudent(){
return currentStudent;
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void ChangeAddress(String newAddress){
currentStudent.setAddress(newAddress);
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void SubmitAssignment(Assignment submittedAssignment){
}
}
#ManagedBean
#SessionScoped
public class LoginSession{
#EJB
private StudentDao studentDao;
public login(String sid){
studentDao.login(sid);
}
}
assignment.xhtml:
<h:datatable value="#{loginSession.studentDao.currentStudent.submittedAssignments}"></h:datatable>
As the currentStudent lives with the extended persistence context, I can retrieve the information directly. And I do not have to pass SID to EJB again and again for each operation, also applies for finding that student again and again as it is already there managed.
I am not sure if it is an abuse of #Stateful bean as the pages had been a large group of conversations, unlike the common "shopping cart" example where user can choose a lot of orders, make payment, then commit all database changes after validation and user confirm.
Please comment on the above SFSB usage whether it is an abuse of SFSB and why if it is an abuse, or which one of the above two designs is better (or suggest another if both were bad as I am the first time writing a web application starting from scrap but a few books from Apress, those started with Pro whatever, EJB3, JPA, JSF, Java EE 6 with glassfish etc).
Thank you.
If you use stateful session beans, the EJB container manages state on behalf of your client, so there is no need to pass around an ID: It's more comfortable.
In your case it's OK.
Generally speaking, consider these items:
Stateless services are sometimes a little bit easier to test: If you write a test case, you do not have to consider the side-effects on the state.
If your stateful session bean holds cached data, you have to handle cache invalidation.
If your session bean is #Remote: If client and server are not on the same JVM, each method call requires marshalling, and goes over the network.
If you have lots of stateful sessions which consume resources on the server side: You already have two Lists there, and their number and their content will most likely grow over the time. Using a stateless setup, you can design an application where the state is only managed in the browser, for example.
If someone else is using your comfortable stateful API, and you must change it later, you will have endless discussions.
For these reasons I always prefer the stateless setup using data transfer objects. But again, in your case it's OK.
I' have a question about initialization of List in the POJO as it follows the next code:
public class Person {
//other fields...
private List<String> friends=new ArrayList<>();
public List<String> getFriends() {
return friends;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
}
OR is it better like this and have initalization in other class(like for example Bean(JSF))
public class Person {
//other fields...
private List<String> friends;
public List<String> getFriends() {
return friends;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
}
So my question is what approach is better?
If it's a managed bean as you say, you should do this in a method annotated with #PostConstruct
public class Person {
private List<String> friends;
#PostConstruct
public void init(){
friends = new ArrayList<String>();
}
//getter and setter...
}
The practice of doing any initialization in the getter and setter is generally frowned upon within the context of JSF. See Why JSF calls getters multiple times
Also, per the API for #PostConstruct, the contract specifies safety features and guarantees that if an exception is thrown in a method annotated as such, the bean should not be put into service. There are no such guarantees on a plain constructor.
In a managed bean, injection happens immediately after construction. This means that any operations you're carrying out in the constructor cannot depend on any injected resources (via #ManagedProperty). Whereas in a #PostConstruct method, you'll have access to all the resources declared on the managed bean
EDIT: It's important to note that there can be only one #PostConstruct for any #ManagedBean, so all important initializations should happen in there.
It's also worthwhile to note that, while the #PostConstruct method is the ideal place to initialize a backing bean variable/List, there are implications regarding the scope of the managed bean
#RequestScoped: In a managed bean with this annotation, the method will be called per submit of the JSF view concerned. A #RequestScoped bean is destroyed and recreated with every request, The implication of this is that depending on your setup, the list initialized in the #PostConstruct may be reset to empty or default values during each request. Under certain circumstances, conversion errors may occur as a result of the re-initialization of the list mid-JSF request.
#ViewScoped: In a managed bean with this annotation, you're guaranteed to have the #PostConstruct method run once, if and only if you're dealing with the same instance of the #ViewScoped bean. If the viewscoped bean is destroyed and recreated, the #PostConstruct method will run again.
#SessionScoped: A bean with this annotation is created once and stays alive until the user's HTTP session ends. In this scenario, the #PostConstruct method is guaranteed to run once and only once until the bean is destroyed
See also
https://stackoverflow.com/a/3406631/1530938
I would suggest this:
public class Person {
//other fields...
private List<String> friends=new ArrayList<>();
// returns a copy to protect original list
public List<String> getFriends() {
Collections.unmodifiableList(new ArrayList<>(friends));
}
public void addFriend(String> friend) {
this.friends.add(friend);
}
public void addFriends(List<String> friends) {
this.friends.addAll(friends);
}
}
In my opinion it would be best to handle that in the constructors. If a default constructor is used, initialize the list in the constructor.
public Person() {
friends = new ArrayList<>();
}
If a constructor which accepts parameters is used, let the calling class pass in a list.
public Person(ArrayList<> friends) {
this.friends = friends;//friends
}
My suggestion, add a null check in the getter:
public class Person {
//other fields...
private List<String> friends;
public List<String> getFriends() {
if (this.friends == null) friends = new ArrayList<String>();
return friends;
}
}
But also notice I have omitted the setter. Instead, in any client code, call like this:
personInstance.getFriends().add("Some Item");
Or if you have a full list to add:
personInstance.getFriends().addAll(someStringCollection);
It depends. Usually first way preferable because you may want to add something to collection later. If you won't know was your collection initialized or not you must check it every time.
I'm using JSF and am running in a problem for quite awhile, I've searched at a lot of places but couldn't find any suitable answer.
Can I have dependency injection working in an abstract (or more generally a class higher in the hierarchy) class ?
Also, how should we handle annotations when working with inheritance ? I've read that the common practice would be not to annotate the abstract class, only the concrete one, but then, it would imply no injection for that abstract ?
My problem is that one (check the last comment) :
Abstract class
#ManagedBean
#ViewScoped
public abstract class AbstractController<T extends VersionedObject> implements Serializable {
#ManagedProperty("#{libraryVersionController}")
private LibraryVersionController libraryVersionController;
public List<T> loadFromDatasource(IVersionedServiceBase<T> service) {
log.info("Loading generic VO from data source");
VersionedObjectFilter filter = new VersionedObjectFilter();
filter.setSelectedLibVersion(libraryVersionController.getSelectedItem());
// etc
}
// getters, setters...
}
Concrete class
#ManagedBean
#ViewScoped
public class DomainController extends AbstractController<Domain> implements Serializable {
private List<Domain> allItems;
private Domain[] selectedItem;
#ManagedProperty(value = "#{domainService}")
private DomainService domainService;
#PostConstruct
public void loadFromDatasource() {
allItems = super.loadFromDatasource(domainService);
// !! DOES NOT WORK, null pointer exception on abstract class (libraryVersionController)
// etc
}
Getters and setters are correctly set up, as I could read in my .xhml it is the concrete class that I'm referencing (#{domainController.allItems}), there is only one #PostConstruct. I'm using JSF2.1 and Mojarra.
Thanks for your help !
As to your NullPointerException, my guess is that AbstractController.setLibraryVersionController is missing. As I understand it, when the AbstractController is constructed (presumably it has an implicit constructor even though it's abstract), that method is needed to fill in the appropriate value.
I know you said all getters and setters are there, but this one seems tricky, so possibly you missed it. If you add logging to this method, you can check that JSF is attempting to fill in the value, and also check whether the value is null or not.
On the general question of how dependency injection works with the inheritance hierarchy, I would guess that your approach is OK, and that dependencies are injected for the base class and then for the derived class, down the chain.
I have a request scoped CDI manage bean(Also tried with jsf managed bean but the same problem!) :
#Named
#RequestScoped
public class myController{
private HashMap<String, MyModel> modelMap;
#PostConstruct
private void init() {
logModelMap = new HashMap<String, MyModel>();
logModelMap.put("CONSTANT_1", new MyModel());
logModelMap.put("CONSTANT_2", new MyModel());
logModelMap.put("CONSTANT_4", new MyModel());
}
public HashMap getModelMap() {
return logModelMap;
}
}
And MyModel class which is a simple pojo:
public class MyModel{
private String type = "";
private Date date;
//constructor, getter and setter methods
}
I have written a composit component using jsf and bind fields to textbox and calendar and I want to access fields inside hashmap and set some values:
#{myController.modelMap['CONSTANST_1'].type}
#{myController.modelMap['CONSTANST_1'].date}
#{myController.modelMap['CONSTANST_2'].type}
#{myController.modelMap['CONSTANST_2'].date}
#{myController.modelMap['CONSTANST_3'].type}
#{myController.modelMap['CONSTANST_3'].date}
but just the first two lines for constant_1 works and for other two constants, type and date are null !
I saw in firebug that values are sent to server properly but fields inside map are not set!
By the way I'm using primefaces command button with ajax to send data to server.
Finally I got where the problem was.
I had nested forms!!!
One form that wraps my composite component and one form where I used my composite component!