I have a HTML table that's generated in a JSP by the displaytag tag library. I would like to suppress any zeros that appear in the table, i.e. they should be replaced by a blank cell. Is there any straightforward way to achieve this?
I discovered that this can be achieved using a custom implementation of ColumnDecorator.
public class SuppressZeroDecorator implements DisplaytagColumnDecorator {
/* (non-Javadoc)
* #see org.displaytag.decorator.DisplaytagColumnDecorator#decorate(java.lang.Object, javax.servlet.jsp.PageContext, org.displaytag.properties.MediaTypeEnum)
*/
public Object decorate(Object rowObject, PageContext pageContext, MediaTypeEnum mediaType) {
if (rowObject != null && rowObject.toString().trim().equals("0")) {
return null;
}
return rowObject;
}
}
The decorator should be declared for each column in the JSP like this:
<display:column property="age" title="Age" decorator="com.example.ZeroColumnDecorator" />
Create a org.displaytag.decorator.TableDecorator instance, and place it into the table. Use the display:table tag's decorator attribute to place your fully qualified decorator class name into the table (I believe you can instantiate one and then place it in, but this class instantiation is trivial...make sure you have a no-arg constructor for this to work properly).
The methods initRow(...) or startRow() are where you would go through your table object, setting any zeroes you find to null (or, if displaying nulls, a blank space). I recommend initRow, but make sure you use super.initRow() first to easily access the current row object. The reason I recommend this is that startRow must return a String (defaults to returning a null string) which I don't think you need to do.
To my knowledge there isn't an "straightforward" way of handling this. The only data-related config property is whether to display nulls or not.
You're better off handling this before the data gets to to the displaytag tag. Perhaps in the servlet that provides the data or a view helper class.
Related
Context:
I am building an Excel document in a generic way with data i receive from a SOAP service endpoint. I receive the data as a List and i have the model (JavaBeans) for every Object i receive according to the method called.
So I set the first row of the sheet as the header from the object's fields (getDeclaredFields).
Then i go on filling up the column row by row with values from the list of objects.
The problem:
I haven't found a workable way of getting the object's field values.
I have tried using the getters with the java reflection API with something like this answer's https://stackoverflow.com/a/5503534/4807777 findGetterName , findGetter however the PropertyDescriptor's getName sometimes is a different letter case from the field name as obtained from the class's getDeclaredFields.
Let's say i overcome this by capitalizing both names, the getReadMethod stil fails - doesn't seem to find getters for the fields which use the is prefix (i.e boolean fields). I don't know if i am misusing it or it is a bug (debugging the getReadMethod appears to only work with the get prefix, even though it appears to handle the is prefix case for booleans).
Considering the fact the fields aren't accesible outside of the object's package, therefore solely through invoking getters.
Is there a better way of obtaining the object's field getters or i am missing something with the getter methods?
Update: Spring's BeanUtils seems to be better for getting the properties with it's getPropertyDescriptors is better than java Class's getDeclaredFields, when the JavaBean properties are mapped to XML elements.
This fixes the different letter cases situation. However it stil doesn't find it's readMethod when not using the get prefix.
Edited - to show an example of getReadMethod not finding the is prefixed getter, as Laszlo Lugosi requested.
A simple class:
class Test {
private String assignmentType;
private Boolean conserved;
public String getAssignmentType() {return assignmentType;}
public void setAssignmentType(String assignmentType) {this.assignmentType = assignmentType;}
public Boolean isConserved() {return conserved;}
public void setConserved(Boolean conserved) {this.conserved = conserved;}
}
Run this with the findGetter and findGetterName written in the answer linked above:
{
Test obj = new Test();
obj.setAssignmentType("someType");
obj.setConserved(true);
Field[] fields = obj.getClass().getDeclaredFields();
String fieldName;
for (int i=0;i<fields.length;i++){
fieldName = fields[i].getName();
java.lang.reflect.Method method;
Object val = null;
try {
method = obj.getClass().getMethod(findGetterName(obj.getClass(),fieldName));
val = method.invoke(obj);
}
catch (Exception e){
e.printStackTrace();
}
}
}
Edited 2
While i could simply write a getReadMethod following the convention Laszlo Lugosi highlighted i do prefer finding an API for handling accessors.
As you know only the object field name, and JavaBean has convention, you can figure out the getters easily. The rules are getUpperfieldname() and isUpperfieldname if field is boolean. And you can find out the return type as well from the object field.
I'm trying to create a simple crud form to insert data into a database with hibernate, without knowing what the object type is. The ultimate goal is to only have one insert form for every table in the database. So far i get the methods that the current object has, check to see if it has any set methods and create a text input for every field that has a set.
UIViewRoot viewRoot = FacesContext.getCurrentInstance().getViewRoot();
HtmlPanelGrid hpg = (HtmlPanelGrid) viewRoot.findComponent("panel");
for (Method method : declaredFields) {
String name = method.getName();
if (name.contains("set")) {
HtmlOutputText hot = new HtmlOutputText();
HtmlInputText hit = new HtmlInputText();
hot.setValue(name.substring(3));
try {
hit.setValue(newObject.getClass().getMethod(name, String.class));
} catch (Exception ex) {
Logger.getLogger(ReflectController.class.getName()).log(Level.SEVERE, null, ex);
}
hpg.getChildren().add(hot);
hpg.getChildren().add(hit);
}
}
Here newObject is the object that is going to be inserted into the database later with hibernate. My problem is this:
How do assign a certain field from that object to the text input that is being created at the moment. So far if I put the method in the value like I'm doing above, it will just print out the method in the value attribute for that input. what i want is that when this form is submited, for to assign the value in that text box to the property with that name.
I can give you a partial answer - You need to create a ValueExpression dynamically
Application app = FacesContext.getCurrentInstance().getApplication();
hit.setValueExpression("value", app.getExpressionFactory().createValueExpression(FacesContext.getCurrentInstance().getELContext(), "#{bean.item}", Item.class));
The hard part will be creating the valueExpression that will actually map to a field within your object's value. That requires a great deal more thought but you will for sure need the dynamic valueExpression. As written, this will result in the execution of your bean's setItem();method with a parameter of type Item. You will require something a little more complex.
In JSF, binding input components to properties is accomplished with EL-expressions. You can create one programmatically as Steve shows, but that syntax is really ugly. On a related note, programmatic manipulation of the component tree is a rather unorthodox way of using JSF. The orthodox way to tackle your requirement would be something like:
<ui:repeat var="prop" value="#{genericEditorBean.propertyNames}">
<h:outputLabel value="#{prop}" for="input"/>
<h:inputText id="input" value="#{genericEditorBean.object[prop]}"/>
</ui:repeat>
where
public List<String> getPropertyNames() {
List<String> propertyNames = new ArrayList<>();
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
propertyNames.add(pd.getName());
}
return propertyNames;
}
(There really is no reason to reimplement scanning for Java Bean properties when the Java API offers a class for that very purpose. Unlike your home-grown version, this will also handle properties inherited from a super class ...)
I once used an open-source library named MetaWidget to do this.
It was a few years ago, but it worked well and was easy to set up.
It looks like the project is still active:
http://metawidget.sourceforge.net/index.php
I'm using this tag in a custom view, to generate a CRUD form for my object:
<div class="configForm">
#{crud.form /}
</div>
This generate a CRUD form inside my own view. Is there a way to customize the generated form by removing a few fields that I don't want to be editable?
I spotted this line inside form.html:
#{list items:_fields ?: currentType.fields*.name, as:'fieldName'}
If I'm reading this right, then there is a _fields parameter that might let me opt-in to fields (I prefer opt-out, but I'll take opt-in). How do I use this _fields parameter?
You can filter fields like:
#{crud.form fields:['name', 'email', 'password']/}
which will show only the fields name, email and password
Regards
Ronald
I wrote a filtered version of CRUD's ObjectType. The controller can select which fields to filter, like this:
public static void show(long id) {
MyModel object = MyModel.findById(id);
CRUD.ObjectType type = new FilteredObjectType(MyModel.class,
"filteredField1",
"filteredField2");
render(type, object);
}
You can follow Play documentation. Then you can easily write your own ExtCRUD class which ignores all fields which are declared in a static variable of your Controller. How ever FilteredObjectType is for special cases the easier solution.
When registering a customerEditor in spring to format a number with a given numberFormat instance, it is easy to apply this to a specific field in the jsp, e.g.:
NumberFormat numberFormat = getNumberFormat(0, 0, 2);
PropertyEditor propertyEditor =
new CustomNumberEditor(Double.class, numberFormat, true);
binder.registerCustomEditor(Double.class, "myDoubleField", propertyEditor);
This will result in a correct format of the number based on the applications locale (regarding commas and dots for thousand/decimal separator) and with the specified decimals before and after the seperator.
However, if I have a list of unknown size containing doubles how can I format these in a smart way? I could of course run through the list and register one for each entry in the list, but it seems cumbersome and wrong.
Since spring is binding to lists with indicises the field names would have names like "myDoubleField[0] .... myDoubleField[n]" which therefore makes it hard...
Is there an easy workaround for this? Or is there a workaround at all?
Thanks a lot in advance, I hope someone can point me in a correct direction!
If you are displaying a list of values in an array/ArrayList and you want to format specific fields in the elements and not just a blanket converter for all Integer objects you can do this:
Firstly the example class I will use:
public class ListOfTimes {
private List<TimeStoredInSecondsSinceMidnight> times;
public static class TimeStoredInSecondsSinceMidnight {
private Integer id;
private Integer currentTime;
...
}
...
}
Imagine you have an instance with a few times added into it and then it is added into your model as timesList. In the foreach loop of your view you have something like this:
<form:input id="time" path="times[${count.index}].currentTime" size="5"/>
<form:input id="recordId" path="times[${count.index}].id" size="5"/>
Of course this will result in a list of input boxes with your integers in but if you apply a property editor like this:
binder.registerCustomEditor(Integer.class, propertyEditor);
propertyEditor will be invoked on both id and currentTime, not what is desired. If we add the field name to the registerCustomEditor call it will not work either (neither id or currentTime are edited with propertyEditor):
binder.registerCustomEditor(Integer.class, "currentTime", propertyEditor);
Because the name has [n] for each element... after finding this:
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/validation/DataBinder.html#registerCustomEditor%28java.lang.Class,%20java.lang.String,%20java.beans.PropertyEditor%29
Reading the comments in the above link says that the following will do what we want:
binder.registerCustomEditor(Integer.class, "times.currentTime", propertyEditor);
id is untouched (uses the default editor) and currentTime uses the custom propertyEditor.
I know this is probably old news to most Spring MVC devs but I found this page and I am sure others will too.
Solved by replacing old cumbersome way of registering custom editors, by using a global PropertyEditorRegistrar.
Initializing controllers with this in constructor:
public myController(PropertyEditorRegistrar customPropertyEditorRegistrar) {
this.customPropertyEditorRegistrar = customPropertyEditorRegistrar;
}
and registering this in initBinder:
#Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
customPropertyEditorRegistrar.registerCustomEditors(binder);
}
Forces all elements to be formatted in the way specified in the CustomerPropertyEditorRegistrar.
Eg. with doubles:
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
// Double
PropertyEditor doubleEditor = getLocaleBasedNumberEditor(Double.class, true);
registry.registerCustomEditor(double.class, doubleEditor);
registry.registerCustomEditor(Double.class, doubleEditor);
}
Specific fields can the be overwritten in the old manner, if another formatting is desired for a specific field.
//Hoof
Every field in that list should have the same number format, right?
I'm not sure if this going to work,
but you can try to register default editor, and redefine editors for other fields:
binder.registerCustomEditor(Double.class, defaultEditor);
binder.registerCustomEditor(Double.class, "field1", specificEditor1);
binder.registerCustomEditor(Double.class, "field2", specificEditor2);
I'm using Spring, but this question applies to all JSP-controller type designs.
The JSP page references data (using tags) which is populated by the corresponding controller. My question is, where is the appropriate place to perform formatting, in JSP or the controller?
So far I've been preparing the data by formatting it in my controller.
public class ViewPersonController extends org.springframework.web.servlet.mvc.AbstractController
{
private static final Format MY_DATE_FORMAT = new SimpleDateFormat(...);
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
{
Person person = get person from backing service layer or database
Map properties = new HashMap();
// No formatting required, name is a String
properties.put("name", person.getName());
// getBirthDate() returns Date and is formatted by a Format
properties.put("birthDate", MY_DATE_FORMAT.format(person.getBirthDate()));
// latitude and longitude are separate fields in Person, but in the UI it's one field
properties.put("location", person.getLatitude() + ", " + person.getLongitude());
return new ModelAndView("viewPerson", "person", properties);
}
}
The JSP file would look something like:
Name = <c:out value="${person. name}" /><br>
Birth Date = <c:out value="${person. birthDate}" /><br>
Location = <c:out value="${person. location}" /><br>
I know that JSP does have some provisions for formatting,
<%# taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<fmt:formatDate type="date" value="${person. birthDate}" />
But this only works with Java's java.util.Format. What if I need more complex or computed values. In such a case putting the code in the JSP would be cumbersome (and ugly).
I'm curious if this is following the spirit Spring/JSP/MVC. In other words, is the controller part of the view? Where is the preferred place to perform view related formatting? Should my controller just be returning the object (Person) instead of a Map of formatted values?
JSPs typically do not have a lot (or any?) code in them, so your options would be
controller
tag libraries
I would say that a tag library would probably be what you want for most cases, because typically the view is the code that cares about things like formatting.
If standard tag libraries don't get you there, they are not hard to create, so you can roll your own.
I typically do formatting, etc. in the bean or a view "helper". This has several advantages including the following:
Easier to test
Flexibility to change your view technologies without worrying about porting or rewriting what you've done in custom tablibs.
Cleaner and easier to maintain controller and view code.
I prefer to consider formatting part of the display layer, thus done in the JSP. I used Velocity most recently, but same idea with JSP: controller returns a data model, and the view is responsible for rendering that data into a visible representation. Plenty of JSP tag libraries out there for common needs.
You mention complex or computed values. Those sound like elements of the results data model to me, so should be done in the controller, even if they can in principle be determined by other data, such as sum, max and other aggregate values. By formatting in the view I mean basic things like date and number formats, line splitting, alignment. Of course the exact line between data and formatted representation depends on the application, but I think you get the idea.
The way I would do it is -
an instance of the Person class would be the only object in the Model of the ModelAndView
I would move the "presentation logic" into the Person class itself. For example,
public class Person {
public String getLocation() {
return this.latitude.concat(", ").concat(this.longitude);
}
}
I think overall this approach:
1 - strengthens your domain model.
2 - reduces code duplication (what if you wanted to show the location in another JSP? With your approach you'd have a lot of code duplicated)