Iterate through a List property of an object with Struts2 - java

Considering the following:
public class Company {
private String name;
private List<Person> employees;
//getters and setters
}
public class Person {
private String name;
private List<Car> cars;
//getters and setters
}
public class Car {
private String color;
//getter and setter
}
I want to get with Struts2 the color property of every car for every employee. So how would I iterate over the list of cars of every employee of the Company object?
After creating it, I put employees as employeeList into session. Using the following method, I can only get the name property, but can't iterate over the cars property:
<s:if test="#session.employeeList.size() > 0">
<s:iterator value="#session.employeeList">
<s:property value="name" /> //this works
<s:property value="cars" /> //how do I iterate over this list?
</s:iterator>
</s:if>
Doing this, the output for "cars" property is ognl.NoConversionPossible
I tried something like:
<s:if test="#session.employeeList.size() > 0">
<s:iterator value="#session.employeeList">
<s:property value="name" /> //this works
<s:iterator value="cars">
<s:property value="color" />
</s:iterator>
</s:iterator>
</s:if>
but doesn't work that way. Any ideas?
LE: Solution: Actually the iteration works. The objects I was talking about are mapped as Hibernate Entities. The "List cars" property is in fact a #ManyToMany relationship. So, after looking deeper into the error logs I found out that the cars property that I was trying to iterate was not being populated because Hibernate was lazily initializing it by default. I changed the FetchType to EAGER and the problem was solved.

The fact that I use session over the action attributes is not really important. Though, how could I use action attributes in this case? It doesn't seem doable.
Why not ?
Action:
public class MyAction extends ActionSupport {
private Company company; // private attribute
public Company getCompany(){ // public getter
return company;
}
public String execute(){
company = someService.loadTheCompanySomehow();
return SUCCESS;
}
}
JSP:
<s:iterator value="company.employees">
<s:property value="name" />
<s:iterator value="cars">
<s:property value="color" />
</s:iterator>
</s:iterator>
If the inner iteration doesn't work, there is probably something you have not shown to us, or related to the way you've cleaned the code before posting it.

Related

MySQL will or will not return duplicate rows, depending on whether a particular column is present or not. Why?

I'm using Spring Tool Suite Version: 3.9.8.RELEASE
Using a repository that extends CRUD
MySQL table imports CSV file.
The issue that I encountered originally, was that for some reason values under the column "Name" were repeated and also many of the values were missing, when fetching from the database.
I realized after extensive testing that values under "Name" were being duplicated (meaning multiple values would have the same name) but they were also replacing other "Name" values in the database (the ones that were missing).
I got rid of the "Intervals" column and it fixed the problem, meaning all the values were returned, not one missing, and without duplicates. What I think happens is that somehow MySQL goes by what's in the "Intervals" column, as some intervals are duplicates (eg. 10:00-10:30 could be present multiple times, but relating to different Name values)
My question is why did this happen? Is it because of the format the "Intervals" column had? (it's varchar(255) but it's written as "00:00-00:00"
#Controller
public class Patterns {
#Autowired
private PatternRepository repo;
#RequestMapping("")
public String index() {
return "index";
}
#RequestMapping("searchAll")
public ModelAndView patterns() {
ModelAndView mv = new ModelAndView("showinfo");
ArrayList<Pattern> pattern = (ArrayList<Pattern>) repo.findAll();
mv.addObject("pattern", pattern);
return mv;
}
#Entity
public class Pattern {
#Id
#GeneratedValue
public String Intervals;
public String Name;
public String Code;
public String Duration;
public Long Id;
<h1>show info</h1>
<fieldset>
<legend>All Agent Activity</legend>
<table border="1" cellpadding="5">
<tr>
<th>Intervals</th>
<th>Name</th>
<th>Code</th>
<th>Duration</th>
</tr>
<c:forEach items="${pattern}" var = "i" >
<tr>
<td>${ i.intervals }</td>
<td>${ i.name }</td>
<td>${ i.code }</td>
<td>${ i.duration }</td>
</tr>
</c:forEach>
</table>
</fieldset>
MySQL Table
You wrote:
#Entity
public class Pattern {
#Id
#GeneratedValue
public String Intervals;
public String Name;
That means the primary key is "Intervals", not name. Hence, there is no particular restriction on the "Name" attribute (at least in the java code), so there could be duplicates.
If you want "Name " to be the primary key, move #Id on the line right before the declaration of Name.
But you got an attribute called Id, and you probably what this to be the primary key. To make things easier,you also probably want this attribute to be autogenerated, move both #Idand #GeneratedValueright before the declaration of Id
Example:
#Entity
public class Pattern {
public String intervals;
public String name;
#Id
#GeneratedValue
public Long id;
PS: Please, use java naming convention: attributes in camel case: first character in lower case (name, not Name)

Creating drop down list using Spring, Hibernate, JSP

Applications: Hibernate, Spring 3.0 MVC, JSP (used Spring forms)
Requirement: To select a table data from the database using Hibernate and display that as a drop-down list in JSP page using Spring MVC.
Code:
Hibernate / Dao code is
Cuisine class
#Entity
#Table(name = "cuisine")
public class Cuisine {
#Id
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
.. getters and setters
RecipeDaoImpl class
public List<Cuisine> getCuisine() {
String hql = "SELECT id, name FROM Cuisine";
return getSession().createQuery(hql).list();
}
Spring MVC
#Controller
public class RecipeController {
...
#RequestMapping("/add")
public String newRecipe(Map<String, Object> map) {
/* Get cuisine list and new object for cuisine */
List<Cuisine> cuisines = recipeServices.getCuisine();
System.out.println(cuisines);
map.put("cuisineList", cuisines);
map.put("cuisine", new Cuisine());
return "recipes/new";
}
JSP page:
<%# taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<tr>
<th><sf:label path="cuisine">Cuisine</sf:label></th>
</tr>
<tr>
<td><sf:select path="${cuisineList}">
<sf:options items="${cuisine}"></sf:options>
</sf:select></td>
</tr>
On doing it, I am getting following error:
org.springframework.beans.NotReadablePropertyException: Invalid property '[Cuisine [id=1, name=Continental][id=2, name=Italian]' of bean class [com.recipe.tables.Recipe]: Bean property '[Cuisine [id=1, name=Continental][id=2, name=Italian]' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:729)
org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:721)
org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:219)
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
Can someone please suggest how to fix this? I have checked couple of articles and tried to replicate them, but no luck.
I think jsp should be
<td><sf:select path="${cuisine}">
<sf:options items="${cuisineList}" id="id" itemValue="name"></sf:options>
</sf:select></td>
</tr>

Spring MVC + Hibernate: How to handle form with relation

I have problem with adding/updating records with relations. Could please some advice how it should work?
I have two entities: Question and Category:
public class Question {
#Id
#GeneratedValue
private Long questionId;
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category")
private Category category;
and
#Entity
#Table(name = "category")
public class Category {
#Id
#GeneratedValue
private Long categoryId;
private String name;
I have some list of categories and I would like to add new Question with selected Category. So in my QuestionController I have add method:
#RequestMapping(value = "/add", method = RequestMethod.GET)
public ModelAndView add() {
ModelAndView mav = new ModelAndView("question/add");
mav.addObject("question", new Question());
mav.addObject("categoryList", categoryService.getAll());
return mav;
}
and form:
<form:form modelAttribute="question" method="POST" >
Name: <form:input path="name" value="${ques.name}" />
Category: <form:select path="category" items="${categoryList}" />
<input type="submit" value="Add" />
</form:form>
Everything looks good for now (I can fill question name and select category). But I don't know how add POST method should work
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String added(#ModelAttribute Question question, BindingResult bindingResult) {
}
When I try to use above method I have error: Failed to convert property value of type 'java.lang.String' to required type model.Category
I've tried to look for similar problem but I coudln't find anything.. So if someone can help/advice or show link to similar issue I would be grateful!
Cheers!
You need to provide code for Spring that tells it how to convert the string value from the web page back into a Category object. This is done by either:
Adding a PropertyEditor to the DataBinder.
Creating a Converter.
It is a bad practice using hibernate objects to map the form items. There are two solutions
Add another property private transient String categoryString; to the 'Question' class. and map the UI category to this <form:select path="categoryString" items="${categoryList}" />
That way you can avoid the error.
Do not use the hibernate mapping classes for mapping the form items, use POJOs for doing this. and later somewhere in your application map this simple pojo elements onto the hibernate entity.
try changing this line:
<form:select path="category" items="${categoryList}" />
to:
<form:select path="category.categoryId" items="${categoryList}" itemLabel="name" itemValue="categoryId"/>
Then in the added method (post method), retrieve the Category object back from hibernate and set back on question object before saving:
Category selectedCategory = yourHibernateService.getCategoryById(question.getCategory().getCategoryId());
question.setCategory(selectedCategory);

How to get updated list values from JSP in my action?

I have a JSP in which I am iterating over a list and creating an editable table.
<s:iterator value="test" id="countryList">
<tr>
<td><s:textfield name="countryCode" value="%{countryCode}" theme="simple" /></td>
<td><s:textfield name="countryName" value="%{countryName}" theme="simple" /></td>
</tr>
</s:iterator>
My list:
List<Country> test = new ArrayList<Country>();
Country class:
public class Country {
private String countryCode;
private String countryName;
and the getter setters......
and say I populate the list like:
Country country = new Country();
Country country1 = new Country();
country.setCountryCode("1");
country.setCountryName("India");
country1.setCountryCode("2");
country1.setCountryName("US");
test.add(country);
test.add(country1);
Now when I change the values of countrycode and countryname in the JSP, I should get the updated values in my action. But am I not able to. Is there any way to get these updated values.
You need the Country object is created when the params interceptor is populating your list using indexed property access.
<s:iterator value="test" id="countryList" status="stat">
<tr>
<td><s:textfield name="countryList[%{#stat.index}].countryCode" value="%{countryCode}" theme="simple" /></td>
<td><s:textfield name="countryList[%{#stat.index}].countryName" value="%{countryName}" theme="simple" /></td>
</tr>
</s:iterator>
To let the struts populate the list you should use a type conversion annotation or equivalent in the xml configuration.
#Element(value = Country.class)
#Key(value = String.class)
#KeyProperty(value = "countryCode")
#CreateIfNull(value = true)
private List<Country> countryList = new ArrayList<Country>;

JSF2: selectOneMenu with custom selectItems: all items are selected

Thanks to some great articles here, I've been able to build a <h:selectOneMenu /> with selectItems containing objects. After providing a custom FacesConverter and fixing the missing equals()/hashcode() methods, I am able to use it to change the property of the backing bean and write it out to the DB.
The only weird thing is that all HTML <option /> elements of the <select />-element are checked="checked"! In other words: the <h:selectOneMenu /> does not reflect the current value of the bound property!
Details:
Store.java
#Entity
public class Store {
private Long id;
private String name;
#ManyToOne
private Category category;
// getters, setters, equals, hashcode
}
Category.java
#Entity
public class Category {
private Long id;
private String name;
// getters, setters, equals, hashcode
}
editStore.xhtml
<h:form>
....
<h:selectOneMenu value="#{backingBean.store.category}" id="category">
<f:selectItems value="#{backingBean.categorySelectItems}" />
</h:selectOneMenu>
....
</h:form>
BackingBean.java
public class BackingBean {
private Store store;
// inject data-access-facades via #EJB
// Constructor
// getters, setters
public List<SelectItem> getCategorySelectItems
List<SelectItem> items = new ArrayList<SelectItem>();
for (Category cat : categoryFacade.findAll() ) {
items.add(new SelectItem(cat, cat.getName()));
}
return items;
}
// action methods
}
I leave out listing the Category-Converter (it converts between the object and its ID).
The HTML this creates is:
<select id="category" name="category" size="1">
<option value="251" selected="selected">Kosmetik</option>
<option value="222" selected="selected">Sportwaren</option>
</select>
Obviously, store.category can only contain one item... why are both option-elements "selected"? No matter, what category is assigned to the store, the HTML always "selects" all option-elements.
How does JSF now, which SelectItem should be selected?
It's almost certain that the problem is in the equals(..) method, which returns true for all compared objects. Test this, and let your IDE generate the method (together with hashCode())

Categories