Accessing bean properties in JSF 2.0 - java

I have the following model code, which I am supposed to use.
public class Client extends User {
private String userName;
public Client(String firstName, String lastName, String userName){
super(firstName, lastName);
this.userName = userName;
}
//getters and setters
}
public abstract class User {
String firstName;
String lastName;
//getters and setters
}
Now I have created the following bean:
#ManagedBean(name = "client")
#SessionScoped
public class ClientBean implements Serializable {
private final long serialVersionUID = 1L;
private Client client;
public Client getClient(){
return client;
}
public void setClient(Client client){
this.client = client;
}
}
Now I want to set the clients' firstName using this bean in an xhtml page:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<head>
<title>Register as a client</title>
</head>
<body>
<h:form>
First Name:<h:inputText value="#{???}"></h:inputText>
<br/>
<h:commandButton value="Register" action="registered?faces-redirect=true"/>
</h:form>
</body>
</html>
Now my question is: How do I access the clients' firstName? Am I supposed to create a new bean that represents user as well and extend it in ClientBean? (If so, what's the use of having model code at all? I would have double code everywhere?) Or is there any other simpler way to implement this in JSF 2.0?

You will need the following for the page to display the last name correctly.
-- The class User must have a constructor as below along with getters and setters for firstname and lastname.
public User (String firstName, String lastName)
-- Public getter and setter method for username in Client class.
-- In the ClientBean class, I would suggest you change the name to clientBean. Also, change the getter and setter method to public instead of private. You would need to create an object of type client and initialize the client object to some value if you need to display it on the screen. In the code provided, you are not creating an object or giving any value to any of the name properties.
-- In the JSF page, you can access the values using "#{clientBean.client.firstName}"

Make getter and setter public
public Client getClient(){
return client;
}
public void setClient(Client client){
this.client = client;
}
If your Client is null, simply instantiate it.
private Client client = new Client();

You would take this approach with a managed bean and a pojo if you want to for instance persist the values in a database, or do some other magic stuff, like calling a webservice.
To access the first name you write #{client.client.firstName} Indeed it looks a bit awesome, so I suggest give the managed bean another name.
You could create an instance of the pojo in the managed bean:
public class ClientBean implements Serializable {
private Client client = new Client();
...
}
You could also include first name and last name in the managed bean directly, this would make sense in case you are creating the pojo during some action to save the values.
JSF doesn't press you in a corset, instead you can choose the way that fits you.

Related

Thymeleaf form can't handle org.bson.Document type

I have an entity class with fields of type org.bson.Document. These are values that I am not allowed to modify, but when using Spring Data I need to map them in my model class so that after saving the document back to Mongo these values won't be lost. So the document is fetched from Mongo, mapped to a User POJO and then passed to a Thymeleaf form. When I try to send Thymeleaf form back to the controller I get 400 Bad Request "Validation failed for object..." error and I know it's because of these two additional Document fields. How can I pass these fields to Thymeleaf and then back to the controller? They aren't modified in the form, just appear as hidden inputs:
<input id="resetPassword" th:field="${user.resetPassword}" type="hidden"/>
<input id="consents" th:field="${user.consents}" type="hidden"/>
And my User class:
#Data
#Document(collection = "users")
#NoArgsConstructor
public class User {
#Id
private ObjectId id;
private String email;
private String name;
private String surname;
private String phone;
private String password;
private String country;
private SecurityLevel securityLevel = SecurityLevel.LOW;
private Timestamp created = Timestamp.from(Instant.now());
private Boolean blocked = false;
private org.bson.Document resetPassword;
private org.bson.Document consents;
}
It sounds like the object is being successfully injected into the Thymeleaf template, but not parsed correctly in Spring when the form is returned.
You should examine the representation in the web page (expecting json?) and then ensure that you have a handler defined in Spring that can successfully deserialise the returned object.
If the Document type does not have a conventional constructor (no-args or all-args), or some of the fields are 'hidden' (without the standard getXxx and setXxx methods), then Spring will not be able to reconstruct the object when the form is submitted without a custom handler.
Similarly, if there are not getters for all of the fields (And sub fields) of the object, the Thymeleaf template will have an incomplete object embedded that will not upload correctly.
Take a look at this blog post for some further info: https://www.rainerhahnekamp.com/en/spring-mvc-json-serialization/
I solved it by creating a custom Formatter like that:
public class BsonDocumentFormatter implements Formatter<Document> {
#Override
public Document parse(String s, Locale locale) throws ParseException {
return Document.parse(s);
}
#Override
public String print(Document document, Locale locale) {
return document.toJson();
}
}
And then I registered it in my WebMvcConfigureruration:
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new BsonDocumentFormatter());
}

JSF: Binding two values from the same form field

I am setting a value in the login-bean when the user logs-in
using
--Login-bean
setMailNickname(mailnickname);
And in the info page I am able to retrieve the same value using
--InfoPage
<h:inputText value="#{login.mailNickname}" />
Now on the info page I am taking some more info from the user and saving all of them in the database, As one of the value is from the login form bean it is prepopulating on the Info-page but how to assign the same value to the info-page bean variable-
InfoBean.mailNickname
so that it can be saved into the database with the other fields which the user provides.
How can I assign the value to the infopage bean variable?
You can inject LoginBean into InfoBean, so that you can have a reference to its fields. As I understand one of your beans is at least #SessionScoped. You didn't provide that information, so I'd go as far as to guess that LoginBean is used for logging into your application or something like that and InfoBean to hold that information for future reference. Following that chain of thinking your InfoBean would look like that:
#ManagedBean
#SessionScoped
public class InfoBean {
private String mailNickname;
public String getMailNickname() {
return mailNickname;
}
public void setMailNickname(final String mailNickname) {
this.mailNickname = mailNickname;
}
// other fields, methods...
}
and your LoginBean then would hold reference to session-scoped InfoBean:
#ManagedBean
#ViewScoped
public class LoginBean {
private String mailNickname;
public String getMailNickname() {
return mailNickname;
}
public void setMailNickname(final String mailNickname) {
this.mailNickname = mailNickname;
}
#ManagedProperty("#{infoBean}")
private InfoBean infoBean;
public void setInfoBean(final InfoBean infoBean) {
this.infoBean = infoBean;
}
/** Method you use for populating */
public void populateInput(final String mailNicknameFromDb) {
setMailNickname(mailNicknameFromDb);
infoBean.setMailNickname(mailNicknameFromDb);
}
}
Remember about getters and setters for those fields as well as setter for managedProperty and be careful about scopes (you can't for example inject request-scoped bean into application-scoped bean, because the request-scoped one would probably not exist yet when creating application-scoped one).

Conditional object population

Hy guys, I've turning around a problem using Struts2.
Basically I've a form that the user can submit filling different fields. I would like to populate conditionally the right object with the properties insert by the user.
So for example, if the user fill the form in a intermediary way I would like to use the properties for to create an Intermediary object, instead if the user fill the request in entity way, i'll use the properties for to create the Entity object, ecc...
These object share the same interface Request.
Is there any way to use polimorphically properties for to create Intermediary or Entity object?
Suppose this is my two POJO:
public class Intermediary implements Request{
private String name;
private String surname;
private String code;
private String FiscalCode;
private String address;
...
/*Getters and setters */
....
}
public class Entity implements Request{
private String name;
private String surname;
private String code;
....
/*Getters and setters */
....
}
This could be my form into the jsp page:
<s:form action="fillRequest" id="formRichiesta" name="formRichiesta" method="post">
<s:radio id="tipoRichiedente" name="tipoRichiedente" list="richiedenti">
<label>Name</label><s:textfield name="name"/>
<label>Surname</label><s:textfield name="surname"/>
<label>code</label><s:textfield name="code"/>
<label>Adress</label><s:textfield name="adress"/>
<label>Fiscal Code</label><s:textfield name="fiscalCode"/>
</s:form>
<s:submit>
Basically my problem is that I can discover the kind of request the the user trying to fill only ofter submission and watching at the radiobutton state.
Is there any way to mapping the properties into the right object directly instead of creating one big object with all the form properties and then create the right implementation? for to map properties could I use the interface reference?
For example image my action:
public class RequestAction {
private Request request;
....
}
So in my jsp could I use:
<label>Name</label><s:textfield name="request.name"/>
Thanks in advance.

When/where do entities get created on a Java EE web application?

When or where do entities get created?
Do they get created when the XHTML page loads and accesses the entities via the managed bean?
Or do they get automatically created in the managed bean?
Do we need to manually create it from the managed bean's constructor?
Please see the code below (some necessary code might not have been copied.)
The entity would be:
public class PersonalInfo implements Serializable {
#Size(max = 50)
#Column(name = "FIRST_NAME", length = 50)
private String firstName;
// some getters and setters
}
the web page would be:
<h:form>
<h:outputText value="first name"/>
<h:inputText value="#{personalInforController.personalInfo.firstName}" />
<h:commandButton value="hit me"
action="#{personalInforController.create}"
immediate="true"/>
</h:form>
and the backing bean would be:
#Named(value = "personalInfoController")
#SessionScoped
public class PersonalInforController {
#EJB
PersonalInfoFacade ejbFacade;
PersonalInfo personalInfo;
String defaultPage = "index";
public String create() {
try {
ejbFacade.create(personalInfo);
return "prepareCreate";
} catch (Exception e) {
return "success";
}
}
}
In the example code given, the create action indeed doesn't seem to be able to work. The entity must be created by the backing bean before that.
If it's a simple entity, either the constructor or an #PostConstruct method would work. For instance:
#Named(value = "personalInfoController")
#SessionScoped
public class PersonalInforController {
#EJB
PersonalInfoFacade ejbFacade;
PersonalInfo personalInfo;
String defaultPage = "index";
#PostConstruct
public void init() {
personalInfo = new PersonalInfo();
}
public String create() {
try {
ejbFacade.create(personalInfo);
return "prepareCreate";
} catch (Exception e) {
return "success";
}
}
Some notes about the code. It's highly suspicious, and most likely plain wrong, to declare your bean to be #SessionScoped. If personalInfo is being edited in two tabs or windows you'll be in a world of hurt. I suggest making your bean #ViewScoped (for CDI, there's a separate extension made by the Seam3 that enables this, if you can't/won't use this extension consider using #ManagedBean instead of #Named).
Also, you might want to declare your instance variables to be private and give ejbFacade a better name (e.g. personalInfoFacade). I also doubt whether immediate is necessary on the commandButton, and since the outputText is obviously a label for the given inputText, you might want to consider using outputLabel and the for attribute.

Writing a string property of an object with <html:text />

I've got an object in my form that contains various string properties.
When I want to print it in my JSP form I could do it with
<c:out value="${form.company.address}" />
which works perfectly.
Now I want to create an HTML input field. But when I write
<html:text property="company.address" />
I get an error saying
Caused by: javax.servlet.jsp.JspException: No getter method for property company.address of bean org.apache.struts.taglib.html.BEAN
Do you know how I can create an HTML input field with my company's address?
My bean's got the necessary corresponding getters and setters.
The correct way of translating this:
<c:out value="${UFForm.company.address}" />
to Struts is,
<html:text name="UFForm" property="company.address">
It means that there's a request with name UFForm with a bean that contains a method getCompany() (which I'm assuming returns a Company object) and that in turns has a getAddress() getter (if you understand what I mean). In a nutshell, the bean from request/session UFForm, the TagLib is accessing getCompany().getAddress();
PS Hope that getAddress() doesn't return a null else <html:text /> will throw an exception.
Edit To explain what I did above:
public class Company implements Serializable {
private String address;
//Setter
public void setAddress(String address) {
this.address = address;
}
//Getter
public String getAddress() { return this.address; }
}
public class UFForm implements Serializable {
private Company company;
public void setCompany(Company company) {
this.company = company;
}
public void getCompany() {
if (this.company == null) {
setCompany(new Company());
}
return this.company;
}
}
What I did above in <html:text /> is equivalent to
UFForm ufForm = ....;
String property = ufForm.getCompany().getAddress();
Your bean should have corresponding setter and getter methods.
Html form
<html:text property="name" size="10" maxlength="10">
Corresponding bean.
public class AddressForm
{
private String name=null;
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
}
When you are getting the value for the text box with:
<html:text property="company.address" />
You are in fact saying to Struts to do:
formObject.getCompany().getAddress();
So you must have a getter for the company (which must not return null or the next operation will fail) and a setter for the address on the company object. The setters/getters must be public. This must already be the case since you can do the following with no error:
<c:out value="${UFForm.company.address}" />
Now, the thing that bugs me is this part: ${UFForm.. When you use JSTL you are accessing the form explicitly. With the <html:text> you access a property on the form implicitly. This implicit form is provided by the enclosing <html:form> tag. Do you have the <html:text> inside a <html:form>?
The form bean is located/created/exposed based on the form bean specification for the associated ActionMapping so check your mapping also.

Categories

Resources