I'm stuck in a problem with converters and bindings.
I have a page with a form:select where I bind an list of object with itemValue
<form:select id="id_a" items="${items}" path="builder" itemValue="id" />
I've created 2 converter that convert this bean. One convert from the bean to a string displaying the description the other convert from an id to obtain the bean from the DB.
private Converter<BuilderType, String> getBuilderTypeToStringConverter(){
return new Converter<BuilderType, String>(){
public String convert(BuilderType builder){
return builder.getDescription();
}
};
}
private Converter<String,BuilderType> getStringToBuilderTypeConverter(){
return new Converter<String, BuilderType>(){
public BuilderType convert(String id){
return builderService.findById(new Long(id));
}
};
}
So when I create the bean everything works fine, I see the description in the select field and when submit the form the id gets transformed to to the real bean and put into the model attribute before reaching the controller.
the problems is when I try to update, my select is still correctly populated, but the actual value is not selected. There is no option with the attribute "selected" to initialize correctly the select.
That's really strange because I have an sample application (petclinic) of spring roo that actually with the same type of converters populate correctly the select.
The only way I found to get this working is a bit is to add ".id" to the path :
<form:select id="id_a" items="${items}" path="builder.id" itemValue="id" />
But this way on submit I receive back in the controller a empty "builder" with only the id set, not the comprete object I normaly receive when the correct converter gets invoked.
I really have no idea what could be the difference between the two applications that makes one work and not the other... even the spring library version are the same!
I've found the problem. It seems that in the web.xml of working application there was another filter I was not using, just adding this made everything work fine:
<filter>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
It's really strange because nowhere I've found that this was mandatory or even have little a connection with the spring tags to make them work as expected!
I think you should define equals method for the entity class (BuilderType) and compare the instances by id. Otherwise, form generation is not able to find the current value from the list of items for options.
You can verify this by checking calls to equals when implemented in BuilderType.
I was facing the same problem and was able to solve it with help of this comment and the sample code (AbstractEntity.java) in Spring Data book.
Related
I'm wondering if there is a way and if there is, what is the correct one, to use same validation logic (one implementation) for JSF, in EJB beans and web services - rest (RestEasy).
Currently Hibernate entities are used across all layers, because I feel my project is too small to complicate it with additional DTOs on the presentation layer, but the rest service will use DTOs.
How do I approach this problem?
Thanks!
Java EE offers JSR303 Bean Validation API for exactly this purpose. You perhaps already have seen them around, #NotNull and friends. This is by default automatically recognized and supported by both JSF and JPA. JAX-RS usually don't have a "view" which should take/validate input, so it's not of relevance here.
So, instead of e.g. JSF
<h:inputText value="#{bean.entity.property}" required="true" />
with solely
private String property;
you can just use
<h:inputText value="#{bean.entity.property}" />
with
#NotNull
private String property;
This can then also be used by JPA in case you're putting data via JAX-RS.
Only thing you need to take into account in JSF side is that it by default sets empty fields as empty string instead of null. You use the following web.xml context parameter to tell JSF to interpret empty string submitted values as null:
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
See also:
Java EE 7 tutorial - using Bean Validation constraints
Empty input value does not triggger #NotNull but it triggers #NotBlank
I am using Freemarker to render my website pages. I have custom Jsp Taglib references in my pages.
I am experiencing "java.lang.ClassCastException: freemarker.template.SimpleSequence incompatible with java.util.List " while executing 2 related tags sequentially.
<#assign mytag=JspTaglibs["/WEB-INF/tld/mytaglib.tld"]/>
<#mytag.query view="home" params="query params">
<#mytag.process maxItems=10 />
</#mytag.query>
The first tag mytag.query calls a query service and puts the item list to the pageContext.
pageContext.setAttribute("items", resultSet.getItems());
The second tag mytag.process reads the list of items from pageContext and processes them.
List allItems = (List)pageContext.getAttribute("items");
I searched a bit on the Internet and saw that Freemarker has the Object Wrapper feature to wrap the objects that are put to pageContext and convert them to SimpleHash, SimpleSequence and SimpleCollection types in order to make them easily accessible by the templating code. This is explained in the http://freemarker.org/docs/pgui_datamodel_objectWrapper.html
I am not allowed to modify the taglib to not to cast "items" to java.util.List.
Is there a way to tell Freemarker not to convert java.util.List to its SimpleSequence object?
Thanks..
Before 2.3.22: Ugh... that's kind of broken really. It should give you back the original object. But looking at the source code, that only works if you are using a pure BeansWrapper as the objectWrapper (or some custom subclass of it that still returns things wrapped into an AdapterTemplateModel or WrapperTemplateModel, so that FreeMarker can extract the original object).
Update (since 2.3.22):
This is fixed in FreeMarker 2.3.22, but as fixing this is not 100% backward compatible (only 99.99% or like...) you have to activate the fix:
<init-param>
<param-name>incompatible_improvements</param-name>
<param-value>2.3.22</param-value>
</init-param>
This works with DefaultObjectWrapper too, so you shouldn't change the object wrapper from its default. DefaultObjectWrapper with 2.3.22 improvements activated pretty much deprecates pure BeansWrapper anyway.
Alternatively, you can activate 2.3.22 fixes only for the object wrapper (as opposed to the whole Configuration above):
<servlet>
...
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
...
<init-param>
<param-name>object_wrapper</param-name>
<param-value>DefaultObjectWrapper(2.3.22)</param-value>
</init-param>
...
Thanks for the answer.
I think there may be a bug in the FreemarkerServlet because when I tried to set BeansWrapper in the overridden init method like below, it has no effect and it uses the DefaultWrapper.
public void init() throws ServletException {
super.init();
Configuration cfg = getConfiguration();
cfg.setTemplateLoader(new CustomPageTemplateLoader());
cfg.setLocalizedLookup(false);
cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
}
But when I return the ObjectWrapper in the overridden createObjectWrapper method, it worked.
#Override
protected ObjectWrapper createObjectWrapper() {
return ObjectWrapper.BEANS_WRAPPER;
}
This is a question about customisation of Spring's placeholder resolution in #Value annotations.
We initialise all properties in our app using #Value, normally from servlet context init params, eg:
web.xml
<context-param>
<param-name>app.some.param</param-name>
<param-value>SOME_VALUE</param-value>
</context-param>
Class file
#Value("${app.some.param:DEFAULT_VALUE}")
private String myParameter;
We actually don't use web.xml, we use Tomcat context files or even specify using vmargs.
What we'd like to support is dynamic changes to these properties at runtime. I want to somehow collect a list of property keys that are used in #Value and which also have a new annotation like #Dynamic. For properties marked as #Dynamic the bean may provide a corresponding setter, to do any re-initialisation when the property is modified.
I would then like to create a service that supports updating the property by key, eg:
void setProperty(String key, String value) {
// find all beans that have #Value and #Dynamic and set field or call setter
// NB - should support Spring type coercion, eg. string --> integer, boolean, list, etc.
}
I've been looking at the source for PlaceholderConfigurerSupport and BeanDefinitionVisitor. It seems I might be able to override PlaceholderConfigurerSupport.doProcessProperties and create a custom BeanDefinitionVisitor, but there is quite a lot of code to wade through. I wondered if anyone had looked at this before and found a solution.
I should note that there's more we ultimately want to do. We want to persist changed properties in a backing store, and use these instead of the configuration on startup if they've been modified. In this way we'd have a hierarchy of property sources: default in code, context/property files, peristed config that's been modified. We also want to provide a UI showing a set of all dynamic properties. You get the idea.
Thanks
I have been reading this forum for quite awhile and find it VERY useful, thank you to the contributors. I have a question that has plagded me for several weeks. And here it goes.
#RequestMapping(value="updateNote.htm",method=RequestMethod.POST)
public String updateNote(#ModelAttribute("note")NoteBean nb, BindingResult res,Model model){
daoobj.updateNote(nb.getName(),nb.getPath(), nb.getNote());
model.addAttribute("note",daoobj.getByName(nb.getName()));
return("success");
}
#RequestMapping(value="updateNote.htm",method=RequestMethod.GET)
public String updateNote(#ModelAttribute("note")NoteBean nb,Model model){
populateNoteBean();
model.addAttribute("note",daoobj.getByName(nb.getName()));
return("editNote");
}
#ModelAttribute("WHAT")
public NoteBean populateNoteBean() {
NoteBean nnb = new NoteBean();
return nnb;
}
With the method populateNoteBean() the model attribute is "WHAT". But, the name that I use is "note". So when I run the code, the NoteBean is correctly saved to the data base. My question is HOW?? It seems that the name "WHAT" should be "note" or that the model attribute is saving it as no name.
Thank for your time.
With your current code you will have two instances of your notebean in the model!
First spring invokes all modelattribute annotated methods in your controller and places the results in the model. Second it evaluates the ones from your requestmapping method.
The point of a modelattribute annotated method is that you can choose how to create your bean. Load it for example from a database.
We use this approach like that:
modelattr method (name="note")
Loads beans from db
requestmapping method with modelattr param (name="note")
Merges the note bean created by the first method with the request paramters from a submit for example and you habe directly access to the modifed one.
One nice effect:
We do not want to put hidden input fields for all attributes in a form just to be able to merge the entity with the entitymanager. This way you can have a form with only one attribute (plus one for the id to be able to fetch the entity)
Or another one:
If your note bean is an abstract class spring has no possibility to instanciate the bean because it does not know what to instanciate. You can for example add a requestparam parameter in the modelattr annotated method and decide what to do yourself.
This is very well described in the documentation. Either the reference or in the api of either controller, reqestmapping or modelattribute i believe.
This is a spring based application. My form definition in JSP is as below,
<form:form modelAttribute="article" enctype="multipart/form-data" method="POST"
action="${sendEmailUrl}" name="postAd" id="postAd">
I want to display some data from 'article' bean on my form so I've defined modelAttribute='article'. Till here it is all fine. But on submit of the form, I want to collect data in different bean than article. Since I can define modelAttribute only once in the form, can someone please advise how can I use two beans in JSP?
P.S. In case I am not clear, let me give more details. On submit of form, data entered by user will be collected in bean 'X' and email will be sent using java email. But bean 'Y' (article in this case) is holding some values which needs to be displayed on the form.
Hope I am clear.
You could create a FormBean class, containing the two beans you said. Use this new class as a modelAttribute in your form and you will be able to access to both object's properties.
public class FormBean {
public Article article;
public YourOtherObject yourOtherObject;
}