I am new to JavaBeans and I need a little help to keep my first little JSF-project going.
I am writing a little web application where a user can search with certain criteria for buildings. So the user enters in the search form 'location', 'property type', 'asking price', 'number of rooms' and 'living space'.
My managed bean accept the requiry with setter/getter and now the data is to be transmitted to a SQL class, where they are processed and matching search results are returned. It sounds simple, but I can not find a solution.
My managed bean looks like this now:
package beans
//import statements
...
#ManagedBean
#RequestScoped
public class PropertySearchBean {
private String _place
private String _propertyType
private double _askingPrice
private int _rooms
private double _livingSpace
public ArrayList<SearchResults> results = new ArrayList<SearchResults>();
// empty constructor
...
// getter and setter for these 5 user inputs
...
public void initializeSearchResults() {
// do the SQL query, recieve search results
// add it as a new object of 'SearchResults'
SQLPropertySearch search = new SQLPropertySearch(_place, _propertyType,
_askingPrice, _rooms, _livingSpace);
ArrayList<Integer> idResults = search.getPropertyIDlist();
SQLProperty property;
if(!idResults.isEmpty()) {
for(int i=0; i<idResults.size(); i++) {
property = new SQLProperty(idResults.get(i));
results.add(new SearchResults(
property.getPropertyID(),
property.getPropertyName(),
// and so on..
));
}
}
}
public static class SearchResults {
int propertyID;
String propertyName;
// and so on..
public SearchResults(int propertyID, String propertyName) {
this.propertyID = propertyID;
this.propertyName = propertyName;
// and so on..
}
// getter and setter
public int getPropertyID() {
return propertyID;
}
public void setPropertyID(int propertyID) {
this.propertyID = propertyID;
}
// and so on..
}
public ArrayList<SearchResults> getResults() {
return results;
}
}
In my XHTML-file I go through each entry of my ArrayList results.
It looks like this:
<ui:repeat var="res" value="#{PropertySearchBean.results}">
<p>#{res.propertyID}</p>
<p>#{res.propertyName}</p>
</ui:repeat>
I don't have an idea how to initialize the ArrayList, because first thing to do is the search itself, with the user input.
I am thankful for any kind of help!
You've removed the getters and setters from your example to improve readability. I'll provide one implementation here to ensure a common understanding (especially regarding the leading underscores).
public String getPlace() {
return _place;
}
public void setPlace(String place) {
this._place = place;
}
The property 'place' will be accessible within your view by using the value binding #{propertySearchBean.place}(see below).
Your code is meant to perform a search. Therefore you'll have to transfer user input from your XHTML file (view) to your managed bean. To do so you need to add a form to your view. Each search query parameter is bound to your bean using a specific value binding. Additionally the form contains a <h:commandButton> tag which finally triggers initialization of the result list.
<h:form>
<h:outputLabel for="place" value="Place:" />
<h:inputText id="place" value="#{propertySearchBean.place}" />
<!-- Additional fields -->
<h:commandButton action="#{propertySearchBean.initializeSearchResults}"
value="Search"/>
</h:form>
Note: You've used the following code in your example
<ui:repeat var="res" value="#{PropertySearchBean.results}">
Make sure that the first letter of your bean name is lower-case (propertySearchBean instead of PropertySearchBean). So this needs to be updated to
<ui:repeat var="res" value="#{propertySearchBean.results}">
Related
I am trying to get a List of custom object of type linked list into html using Sightly. But I a unable to read them in sightly. Sample Code is pasted below:
Java Bean:
public class MiniNavBean {
private String fPath;
private String activeAttr;
public MiniNavBean(String fPath, String activeAttr){
this.fPath = fPath;
this.activeAttr = activeAttr;
}
public String getFpath() {
return fPath;
}
public void setFpath(String fpath) {
this.fPath = fpath;
}
public String getActiveattr() {
return activeAttr;
}
public void setActiveattr(String activeattr) {
this.activeAttr = activeattr;
}
}
Java class which extends WCMUsePojo:
public class MiniNav extends WCMUsePojo {
private List<MiniNavBean> navList;
MiniNavBean miniNav;
public List<MiniNavBean> getNavList() {
return navList;
}
public void setNavList(List<MiniNavBean> navList) {
this.navList = navList;
}
#Override
public void activate() {
navList = new LinkedList<MiniNavBean>();
fPath = "fpaths";
activeAttr = "activeattrs;"
miniNav = new MiniNavBean(fpath, activeattr);
navList.add(miniNav);
}
}
Html file (Sightly):
<div data-sly-include="/apps/project/components/global.jsp"></div>
<div data-sly-use.mininav="com.components.MiniNav" data-sly-unwrap>
<div data-sly-list.navlist="${mininav.navList}">
<li>
<p>${navlist.fPath}</p>
<p>${navlist.activeAttr}</p>
</li>
</div>
When I am trying to execute the above code, I am able to see the linked list getting instantiated with the data in the java class. However when I am trying to display the values of the list in the front end, sightly is unable to read it.
Since the LinkedList is of CustomObject type(MiniNavBean) I suspect sightly is unable to read it as it doesn't know about this bean because we didn't refer that bean anywhere. Is there a way to fix this using sightly tags and read the data ?
Sightly would loop over Java objects too. I don't think it is issue with Sightly. Looks like your getters are wrong. Change your bean as shown below
public class MiniNavBean {
private String fPath;
private String activeAttr;
public MiniNavBean(String fPath, String activeAttr){
this.fPath = fPath;
this.activeAttr = activeAttr;
}
public String getfPath() {
return fPath;
}
public void setfPath(String fPath) {
this.fPath = fPath;
}
public String getActiveAttr() {
return activeAttr;
}
public void setActiveAttr(String activeAttr) {
this.activeAttr = activeAttr;
}
}
If you do not wish to change the bean, then you can access the getters directly in the Sightly file and check if it is working fine.
<div data-sly-include="/apps/project/components/global.jsp"></div>
<div data-sly-use.mininav="com.components.MiniNav" data-sly-unwrap>
<div data-sly-list.navlist="${mininav.navList}">
<li>
<p>${navlist.getFpath}</p>
<p>${navlist.getActiveattr}</p>
</li>
</div>
EDIT: To explain more based on the comments
You cannot access the fields which are private outside the class and are usually done using the public getter methods. However, in Sightly when you use the field name after the dot operator, you are not accessing the field directly, instead it calls the corresponding getter method based on the Java specification for naming getters / setters. So as per spec, your getters and setters were wrong in the bean due to which it didn't work.
Like I mentioned above, you can change only your bean and your code will work fine. Or you can leave your bean as is and change Sightly code to get things working.
In your example you are neither assigning a value to the navList member of MiniNav nor adding the MiniNavBean instance to it.
Add the following lines to your activate() method:
this.navList = new LinkedList<>();
this.navList.add(navList);
Also, the Java getters and HTL/Sightly accessors are not properly aligned, ie: for getFpath() you should use navlist.fpath
In case you already have those, are you getting any compile or runtime errors from HTL/Sightly?
HTL/Sightly is generally using reflection to lookup properties of objects so it does not care much about their type.
I got folowing message:
Value is no String (class=org.xxx.Foo, value=org.xxx.Foo#366d5595) and component j_id17:j_id114:j_id125with path: {Component-Path : [Class: org.ajax4jsf.framework.ajax.AjaxViewRoot,ViewId: /foo.xhtml][Class: org.ajax4jsf.ajax.html.Include,Id: j_id17][Class: javax.faces.component.html.HtmlForm,Id: j_id114][Class: javax.faces.component.html.HtmlSelectOneMenu,Id: j_id125]} does not have a Converter.
Xhtml:
<h:selectOneMenu value="#{bar.foo}">
<f:selectItem itemValue="#{bar.foos}" />
</h:selectOneMenu>
Foo is:
import javax.faces.model.SelectItem;
#Audited
#Entity
#Table(name= "foo")
#AccessType("property")
public class Foo extends SelectItem implements Serializable{
....
}
Why do i need a converter to convert from SelectItem to SelectItem?
The problem arises when JSF tries to glean the selected value from Foo during display and when it tries to get Foo back from the selected value during a postback. As BalusC mentioned, extending SelectItem isn't a good approach. You have one of two regular options: manually handling the selection or using converters.
Converters are wonderful for adapting pretty much any type of Object so that they can be directly referenced and presented via UI elements. Unfortunately, converters may require extra steps when a conversion isn't simple.
I noticed the #Entity annotation, so I'm assuming you are trying to display a list of records from which the user can choose. 90% of the time, such selections are intended to get a record's primary key rather than the record itself so that it can be used in subsequent queries or business logic. For such situations a manual selection is more effective. However, if you also need to get record content, then a converter is better suited as it would handle the lookup logic and let your business logic work directly with the record.
I'm not going to dictate which method you should choose, but since your original problem was centered around the manual approach, I'll offer this solution. Let's assume your new simplified Foo looks like this.
public class Foo {
private long id;
private String label;
public Foo( long id, String label ) {
this.id = id;
this.label = label;
}
public long getId() {
return id;
}
public void setId( long id ) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel( String label ) {
this.label = label;
}
}
A simple FooCntrl bean as given below would provide presentation information and handle the selection's postback.
#Named
#ViewScoped
public class FooCntrl implements Serializable {
private long selected = 0;
// Stub for what an EntityManager would normally provide.
public List<Foo> getRecords () {
List<Foo> fooList = new ArrayList<Foo>();
fooList.add( new Foo( 11, "Paul" ) );
fooList.add( new Foo( 23, "John" ) );
fooList.add( new Foo( 32, "George" ) );
fooList.add( new Foo( 47, "Ringo" ) );
return fooList;
}
public long getSelected() {
return selected;
}
public void setSelected( long selected ) {
this.selected = selected;
System.out.println( "You picked record id: " + selected );
}
public List<Foo> getFooList() {
return getRecords();
}
}
This in turn drives your UI selection menu.
...
<h:form>
<h:selectOneMenu value="#{fooCntrl.selected}">
<f:selectItem itemValue="0" itemLabel="Select One..." />
<f:selectItems value="#{fooCntrl.fooList}" var="r" itemLabel="#{r.label}" itemValue="#{r.id}"/>
</h:selectOneMenu>
<h:commandButton value="Submit" />
</h:form>
...
This is just one variant. I'm certain that some will disagree with it and recommended converters all the way or even recommend another manual approach. My goal is to give you something that you can move forward with. I'll leave it up to you to refine your design methodology and style at your own pace :).
I'm sending this parameter to my struts action
cdata[1]=bar
In my action I'm interested in the index and the value.
I defined a getter/setter pair for CDATA as the OGNL documentation suggests:
public void setCdata(int index, String value){
LOG.info("setData; key="+ key +"; value="+ value);
// store index and value;
}
public String getCdata(int index){
return null; // don't really need a setter
}
This is the Exception I get:
2013-04-29 15:38:49,792 [http-apr-8080-exec-3] WARN com.opensymphony.xwork2.util.logging.commons.CommonsLogger.warn(CommonsLogger.java:60) - Error setting expression 'cdata[1]' with value '[Ljava.
lang.String;#4223d2a4'
ognl.OgnlException: target is null for setProperty(null, "1", [Ljava.lang.String;#4223d2a4)
at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:2309)
at ognl.ASTProperty.setValueBody(ASTProperty.java:127)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
at ognl.SimpleNode.setValue(SimpleNode.java:301)
at ognl.ASTChain.setValueBody(ASTChain.java:227)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
at ognl.SimpleNode.setValue(SimpleNode.java:301)
at ognl.Ognl.setValue(Ognl.java:737)
...
If I define a public member variable String[] cdata = new String[1000] I don't see any exception in my log but my setter is not called either. If the member variable is private I get another exception again.
Use the following setup
List<String> cdata = new ArrayList<String>();
public List<String> getCdata() {
return cdata;
}
public void setCdata(final List<String> cdata) {
if (cdata == null) {
this.cdata = new ArrayList<String>();
} else {
this.cdata = cdata;
}
}
submit the values from JSP like cdata[1]=value etc
only requirement is to have the getters/setters. I've tested this Tomcat7 running on java 1.6. You can submit values like cdata[0], cdata[1] likewise
or else you could use a map
private Map<String, String> data = new HashMap<String, String>();
public Map<String, String> getData() {
return data;
}
public void setData(Map<String, String> data) {
this.data = data;
}
JSP can have
<s:form action="indexProperty">
<h3>Test The Map</h3>
<input type="text" name="data['0']"/>
<input type="text" name="data['1']"/>
<s:iterator value="data.entrySet()" var="aData">
<s:property value="#aData.key" />-<s:property value="#aData.value" />
</s:iterator>
<input type="submit" name="submit" value="submit"/>
</s:form>
Gets populated without a issue
My solution (rather an ugly hack):
I made my action class implement ServletRequestAware and in the action iterate over the parameter map from HttpServletRequest, fetch cdata from it and parse it for index and value
I had to change the sent parameter and encode eg cdata[999]=foobar like cdata_999_=foobar because if it looks like an array field struts requires there's a setter/getter for it in the action class.
According to the docs, OGNL provides support for indexing properties of JavaBeans: OGNL Reference Guide:
JavaBeans supports the concept of Indexed properties. Specifically this means that an object has a set of methods that follow the following pattern:
public PropertyType[] getPropertyName();
public void setPropertyName(PropertyType[] anArray);
public PropertyType getPropertyName(int index);
public void setPropertyName(int index, PropertyType value);
You didn't implement all of these methods. Also if you didn't initialize an array, the values could not be set.
You can read more about indexed properties here.
Indexed Properties
An indexed property is an array instead of a single value. In this case, the bean class provides a method for getting and setting the entire array. Here is an example for an int[] property called testGrades:
public int[] getTestGrades() {
return mTestGrades;
}
public void setTestGrades(int[] tg) {
mTestGrades = tg;
}
For indexed properties, the bean class also provides methods for getting and setting a specific element of the array.
public int getTestGrades(int index) {
return mTestGrades[index];
}
public void setTestGrades(int index, int grade) {
mTestGrades[index] = grade;
}
I have a model class in the following structure:
public class User {
public String name;
public Long id;
}
public class Play {
public String name;
public User user;
}
Now i want to have a form based on Play class. So I have an editPlay view which takes Form[Play] as an input.
In the view I have a form which calls an update action on submit:
#form (routes.PlayController.update())
{..}
but I cannot find the right way to bind the user field in a way I'll receive it properly in the controller:
Form<Play> formPlay = form(Play.class).bindFromRequest();
Play playObj = formPlay.get();
According to the API, Form.Field value is always a string. Is there some other way to automatic bind an input to the User Object?
Thanks
You can make use of custom DataBinder
In the play.scla.html:
#form (routes.PlayController.update())
{
<input type="hidden" name="user" id="user" value="#play.user.id"/>
}
in your method in the controller
public static Result update()
{
// add a formatter which takes you field and convert it to the proper object
// this will be called automatically when you call bindFromRequest()
Formatters.register(User.class, new Formatters.SimpleFormatter<User>(){
#Override
public User parse(String input, Locale arg1) throws ParseException {
// here I extract It from the DB
User user = User.find.byId(new Long(input));
return user;
}
#Override
public String print(User user, Locale arg1) {
return user.id.toString();
}
});
Form<Play> formPlay = form(Play.class).bindFromRequest();
Play playObj = formPlay.get();
}
I'm not quite sure I understand your question, but basically I have been handling forms like this:
final static Form<Play> playForm = form(Play.class);
...
public static Result editPlay(){
Form<Play> newPlayForm = form(User.class).bindFromRequest();
Play newPlay = newPlayForm.get();
....
}
I serve and render the template from an action using:
return ok(play_form_template.render(playForm));
Then in the template:
#(playForm: Form[Play])
#import helper._
#helper.form(action = routes.Application.editPlay()) {
#helper.inputText(playForm("name"))
...
}
According this article, I've implemented #ManagedProperty(value="#{settings}") to my backing bean:
BEAN Bde.java:
#Entity
#Table(name="bdeDATA")
#ViewScoped
#ManagedBean(name="BDE")
public class Bde implements Serializable
{
/**/
private static final long serialVersionUID = -705775502999920673L;
#Transient
#ManagedProperty(value = "#{settings}")
private Settings settings;
#Id
private Date create_date;
private Integer person_ID;
public Date getCreate_date() {
return create_date;
}
public void setCreate_date(Date create_date) {
this.create_date = create_date;
}
public Integer getPerson_ID() {
return person_ID;
}
public void setPerson_ID(Integer person_ID) {
this.person_ID = person_ID;
try
{
Settings.PWKITEM = (Pwk)Tools.find(person_ID);
if (Settings.PWKITEM != null) settings.setUserfound(true); /// PROBLEMATIC
}
catch (Exception e)
{
Tools.setErrorMessage("NOT FOUND "+e.getMessage());
}
}
// ManagedProperty settings ---------------------------------------------
public Settings getSettings() {
return settings;
}
public void setSettings(Settings settings) {
this.settings = settings;
}
public void setUserfound (boolean userfound){
settings.setUserfound(userfound);
}
public boolean isUserfound() {
return settings.isUserfound();
}
}
Settings.java:
#SessionScoped
#ManagedBean(name="settings")
public class Settings implements Serializable
{
/**/
private static final long serialVersionUID = 8613411699115714416L;
public static Pwk PWKITEM = new Pwk();
private boolean userfound = false;
public boolean isUserfound() {
return userfound;
}
public void setUserfound(boolean userfound) {
this.userfound = userfound;
}
}
XHTML (ajax call setPerson_ID):
<h:inputText id="persId" value="#{bean.bdeitem.persId}">
<f:ajax event="blur" render="name" execute="#this" />
</h:inputText>
<h:inputText id="name" value="#{bean.pwkitem.name}"/>
Problem is in try/catch:
without the condition, object is found.
when I change the condition for example to if (Settings.PWKITEM != null) System.out.println("HELLO"), HELLO is writen to console.
if i try to add the userfound setter, it is catched ("NOT FOUND").
What I'm doing wrong?
Your question looks seriously confusing. You first show some bean code and then immediately say "I though that is an ajax problem,", before even mentioning any kind of problem. The rest of the question is not much different.
To directly answer the last part of your question though:
Ican't understand, why it find the item an writes the correct name to console, and immediatelly after that, it writes catch exception not found....????
You are accessing Settings statically. The instance you have declared at the class level seems to be useless. It's fully possible that if Tools.find throws an exception and thus no new value is assigned, that there is still an old value in the static Settings.PWKITEM field. There is nothing strange about that.
Do note that the log reads from top to bottom. So it's not that "***" is printed and then the exception is thrown, but the exception is first thrown and "Not Found" is printed, and only thereafter "***" is printed.
Additionally, your approach to all of this looks problematic. Declaring an Entity to also be a (JSF) backing bean is rarely a good idea. Using references to some kind of Service or DAO classes from within an entity is also not always a good idea, but doing this in a method that is supposedly a simple setter for an ID simply looks wrong.
Then using static references is even more wrong and to top if off, using underscores in method and non-static variable names goes against the common Java code convention.