I am migrating from JSF1.2 to 2.1, I changed entries for beans in faces-config.xml to annotations. I try use #ViewScoped instead #RequestScoped and #ManagedProperties(To many params in few classes), but every time i click submit for my form bean with annotated as #ViewScoped is recreated. For #SessionScoped everything works correctyl.
I read few Q&A here, and This article, but i didn't force it to work.
I change JSTL tags to rendered atribute, or c:if with ui:param rendered.
in my web.xml i set params:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>CLIENT</param-value>
</context-param>
I tried javax.faces.PARTIAL_STATE_SAVING = true, but didn't work too. With javax.faces.STATE_SAVING_METHOD = SERVER the same problem.
I removed tags handler for test, but it didn't help too.
In project is used: Mojarra 2.1.13, hibernate 3.6, spring 3.1(far as i know updated form 2.x by my predecessor), acegi-security-1.0.5, tomahawk20, urlrewrite-3.2.0.
I use tomcat 6
EDIT:
This is my bean:
package my.package;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import my.package.MyOtherBean;
#ManagedBean(name="someNameBean")
#ViewScoped
//#SessionScoped
public class MyBean extends MyOtherBean {
public MyBean(){
super();
//XXX
System.out.println("-->> someNameBean is being created");
}
}
package my.package;
#ManagedBean(name="someNameMyOtherBean")
//#ViewScoped
#SessionScoped
public class MyOtherBean extends BaseBean {
private ClassWithFormFields dataIn; //getter & setter exist
//a lot of code here
}
Example use of bean
<h:selectOneMenu value="#{someNameBean.dataIn.currencyId}" id="currencyId" tabindex="2" >
<f:selectItems value="#{someNameBean.dataIn..availableCurrencies}"/>
</h:selectOneMenu>
Update
serviceLocalizator is managed by Spring xml files ans JSF annotation
#ManagedBean
public class BaseBean implements Serializable {
private static final long serialVersionUID = 1L;
protected transient Logger log = Logger.getLogger(this.getClass());
#ManagedProperty(value="#{serviceLocalizator}")
protected transient ServiceLocalizator serviceLocalizator;
//few more lines
}
Update 2:
It's My fault. Thanks for #kolossus that he the indicated direction.
I i was looking for answer and I found and read BalusC article And now i now, i shouldn't return string in backing bean action. With null instead string it works. I badly understood concept of a view, I thought that ViewSoped bean id live as long as tab/windows is the same. Now i know that is it JSF View.
I'am sory for a trouble.
Maybe is a way to use #ViewSoped with redirect to new page?
NB: If you reference the same (non-session scoped) bean from 2 different views, two instances of that bean will be created
Navigating in JSF is very basic and straightforward from whatever kind of a bean that is backing a JSF view.
return the name (view id) of the page you're trying to navigate to as the return value of a public method
public String navigateAway(){
//Do whatever processing you want here
return "page2"; //where page2 is the name of an actual .xhtml file in your application
}
Return a JSF navigation case outcome as specified in a faces_config.xml file
public String navigateAway(){
//Prior processing
return "go somewhere else" ; //where go somewhere else is a navigation outcome you've specified in your faces_config.xml file
}
In your faces_config.xml file, you'll have this
<navigation-rule>
<from-view-id>/register.xhtml</from-view-id>
<navigation-case>
<from-outcome>go somewhere else</from-outcome>
<to-view-id>/review_registration.xhtml</to-view-id>
<redirect/>
</navigation-case>
If you want to remain on the same page after an action however, just return null instead of a string in your method and you will not be taken to another view. Also, depending on the scope of your backing bean, you can be sure you will be using the same instance of the bean if you return a null value
For more detail look here
Related
I have Bean validation working nicely in my application. Now I want to check that a new user does not choose a username that has already been chosen.
In the actionlistener I have the code that checks the database but how do I force the user to be sent back to the page they were on if they choose an already existing username?
Introduction
You can do it, but JSF ajax/action/listener methods are semantically the wrong place to do validation. You actually don't want to get that far in JSF lifecycle if you've wrong input values in the form. You want the JSF lifecycle to stop after JSF validations phase.
You want to use a JSR303 Bean Validation annotation (#NotNull and friends) and/or constraint validator, or use a JSF Validator (required="true", <f:validateXxx>, etc) for that instead. It will be properly invoked during JSF validations phase. This way, when validation fails, the model values aren't updated and the business action isn't invoked and you stay in the same page/view.
As there isn't a standard Bean Validation annotation or JSF Validator for the purpose of checking if a given input value is unique according the database, you'd need to homegrow a custom validator for that.
I'll for both ways show how to create a custom validator which checks the uniqueness of the username.
Custom JSR303 Bean Validation Annotation
First create a custom #Username constraint annotation:
#Constraint(validatedBy = UsernameValidator.class)
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public #interface Username {
String message() default "Username already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
With this constraint validator (note: #EJB or #Inject inside a ConstraintValidator works only since CDI 1.1; so if you're still on CDI 1.0 then you'd need to manually grab it from JNDI):
public class UsernameValidator implements ConstraintValidator<Username, String> {
#EJB
private UserService service;
#Override
public void initialize(Username constraintAnnotation) {
// If not on CDI 1.1 yet, then you need to manually grab EJB from JNDI here.
}
Override
public boolean isValid(String username, ConstraintValidatorContext context) {
return !service.exist(username);
}
}
Finally use it as follows in model:
#Username
private String username;
Custom JSF Validator
An alternative is to use a custom JSF validator. Just implement the JSF Validator interface:
#ManagedBean
#RequestScoped
public class UsernameValidator implements Validator {
#EJB
private UserService userService;
#Override
public void validate(FacesContext context, UIComponent component, Object submittedAndConvertedValue) throws ValidatorException {
String username = (String) submittedAndConvertedValue;
if (username == null || username.isEmpty()) {
return; // Let required="true" or #NotNull handle it.
}
if (userService.exist(username)) {
throw new ValidatorException(new FacesMessage("Username already in use, choose another"));
}
}
}
Finally use it as follows in view:
<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
Note that you'd normally use a #FacesValidator annotation on the Validator class, but until the upcoming JSF 2.3, it doesn't support #EJB or #Inject. See also How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired.
Yes you can. You can do validation in action listener method, add faces messages if your custom validation failed, then call FacesContext.validationFailed() just before return.
The only problem with this solution is, it happens after the JSF validation and bean validation. I.e., it is after the validation phase. If you have multiple action listeners, say listener1 and listener2: if your custom validation in listener1 failed, it will continue to execute listener2. But after all, you'll get validationFailed in AJAX response.
It's better to use action method instead of actionListener for this purpose. Then you can return null (reloads page that triggered the action) from this method if the username exists. Here's an example:
in the facelet:
<h:commandButton action="#{testBean.doAction}" value="and... Action"/>
in the bean:
public String doAction() {
if (userExists) {
return null;
} else {
// go on processing ...
}
}
If you want to provide feedback to end-user:
xhtml:
<p:commandButton value="Go" process="#this" action="#{myBean.checkEntity()}" oncomplete="if(args.validationFailed){PF('widgetOldInfoNotice').show();}"/>
<p:confirmDialog id="dialogOldInfoNotice" header="NOTICE" severity="alert" widgetVar="widgetOldInfoNotice">
-- feedback message--
<p:button value="Ok" onclick="PF('widgetOldInfoNotice').hide();"/>
</p:confirmDialog>
bean:
public String checkEntity() {
if (!dao.whateverActionToValidateEntity(selectedEntity)) {
FacesContext context = FacesContext.getCurrentInstance();
context.validationFailed();
return "";
}
return "myPage.xhtml";
}
You can define a navigation case in the faces-config.xml file. This will allow you to redirect the user to a given page depending on the return value of the bean.
In the example below a suer is redirected to one of two pages depending on the return value of "myMethod()".
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>true</from-outcome>
<to-view-id>/correct.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>false</from-outcome>
<to-view-id>/error.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
I have Bean validation working nicely in my application. Now I want to check that a new user does not choose a username that has already been chosen.
In the actionlistener I have the code that checks the database but how do I force the user to be sent back to the page they were on if they choose an already existing username?
Introduction
You can do it, but JSF ajax/action/listener methods are semantically the wrong place to do validation. You actually don't want to get that far in JSF lifecycle if you've wrong input values in the form. You want the JSF lifecycle to stop after JSF validations phase.
You want to use a JSR303 Bean Validation annotation (#NotNull and friends) and/or constraint validator, or use a JSF Validator (required="true", <f:validateXxx>, etc) for that instead. It will be properly invoked during JSF validations phase. This way, when validation fails, the model values aren't updated and the business action isn't invoked and you stay in the same page/view.
As there isn't a standard Bean Validation annotation or JSF Validator for the purpose of checking if a given input value is unique according the database, you'd need to homegrow a custom validator for that.
I'll for both ways show how to create a custom validator which checks the uniqueness of the username.
Custom JSR303 Bean Validation Annotation
First create a custom #Username constraint annotation:
#Constraint(validatedBy = UsernameValidator.class)
#Documented
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public #interface Username {
String message() default "Username already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
With this constraint validator (note: #EJB or #Inject inside a ConstraintValidator works only since CDI 1.1; so if you're still on CDI 1.0 then you'd need to manually grab it from JNDI):
public class UsernameValidator implements ConstraintValidator<Username, String> {
#EJB
private UserService service;
#Override
public void initialize(Username constraintAnnotation) {
// If not on CDI 1.1 yet, then you need to manually grab EJB from JNDI here.
}
Override
public boolean isValid(String username, ConstraintValidatorContext context) {
return !service.exist(username);
}
}
Finally use it as follows in model:
#Username
private String username;
Custom JSF Validator
An alternative is to use a custom JSF validator. Just implement the JSF Validator interface:
#ManagedBean
#RequestScoped
public class UsernameValidator implements Validator {
#EJB
private UserService userService;
#Override
public void validate(FacesContext context, UIComponent component, Object submittedAndConvertedValue) throws ValidatorException {
String username = (String) submittedAndConvertedValue;
if (username == null || username.isEmpty()) {
return; // Let required="true" or #NotNull handle it.
}
if (userService.exist(username)) {
throw new ValidatorException(new FacesMessage("Username already in use, choose another"));
}
}
}
Finally use it as follows in view:
<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
Note that you'd normally use a #FacesValidator annotation on the Validator class, but until the upcoming JSF 2.3, it doesn't support #EJB or #Inject. See also How to inject in #FacesValidator with #EJB, #PersistenceContext, #Inject, #Autowired.
Yes you can. You can do validation in action listener method, add faces messages if your custom validation failed, then call FacesContext.validationFailed() just before return.
The only problem with this solution is, it happens after the JSF validation and bean validation. I.e., it is after the validation phase. If you have multiple action listeners, say listener1 and listener2: if your custom validation in listener1 failed, it will continue to execute listener2. But after all, you'll get validationFailed in AJAX response.
It's better to use action method instead of actionListener for this purpose. Then you can return null (reloads page that triggered the action) from this method if the username exists. Here's an example:
in the facelet:
<h:commandButton action="#{testBean.doAction}" value="and... Action"/>
in the bean:
public String doAction() {
if (userExists) {
return null;
} else {
// go on processing ...
}
}
If you want to provide feedback to end-user:
xhtml:
<p:commandButton value="Go" process="#this" action="#{myBean.checkEntity()}" oncomplete="if(args.validationFailed){PF('widgetOldInfoNotice').show();}"/>
<p:confirmDialog id="dialogOldInfoNotice" header="NOTICE" severity="alert" widgetVar="widgetOldInfoNotice">
-- feedback message--
<p:button value="Ok" onclick="PF('widgetOldInfoNotice').hide();"/>
</p:confirmDialog>
bean:
public String checkEntity() {
if (!dao.whateverActionToValidateEntity(selectedEntity)) {
FacesContext context = FacesContext.getCurrentInstance();
context.validationFailed();
return "";
}
return "myPage.xhtml";
}
You can define a navigation case in the faces-config.xml file. This will allow you to redirect the user to a given page depending on the return value of the bean.
In the example below a suer is redirected to one of two pages depending on the return value of "myMethod()".
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>true</from-outcome>
<to-view-id>/correct.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>false</from-outcome>
<to-view-id>/error.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
I had this working before, but then I changed some things, and I can't get it to work again. I am trying to use my service tier to hit the database and get a correct object from my converter class, depending on what the user clicks. I inject the service property into my converter with spring. During debugging, I can see that the property gets sets properly. But then when I go to call getService, it is null.
#FacesConverter("PlaceConverter")
#SessionScoped
public class PlaceConverter implements Converter {
private SearchQueryService searchQueryService;
/**
* #return the searchQueryService
*/
public SearchQueryService getSearchQueryService() {
return searchQueryService;
}
/**
* #param searchQueryService the searchQueryService to set
*/
public void setSearchQueryService(SearchQueryService searchQueryService) {
this.searchQueryService = searchQueryService;
}
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String submittedValue) {
try {
Criteria criteria = new Criteria();
criteria.setId(Integer.parseInt(submittedValue));
return getSearchQueryService().findPlaces(criteria).get(0);
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
((Place) value).setCategory(" (" + ((Place) value).getCategory() + ")");
return String.valueOf(((Place) value).getPlaceId());
}
}
<bean id="placeConverterBean" class="com.ghghg.converter.PlaceConverter">
<property name="searchQueryService" ref="searchQueryServiceBean" />
</bean>
Dependency injection in a converter works only if the converter is declared as a managed bean by the dependency injection framework in question. E.g. JSF's own #ManagedBean, or CDI's #Named, or Spring's #Component. You should remove the #FacesConverter altogether and reference the converter instance in EL scope instead of referencing it by the converter ID.
Thus, so
<h:inputXxx converter="#{placeConverter}" />
or
<f:converter binding="#{placeConverter}" />
instead of
<h:inputXxx converter="PlaceConverter" />
or
<f:converter converterId="PlaceConverter" />
Your concrete problem suggests that you were referencing it by converter ID (thus, via #FacesConverter). This way you end up getting a converter instance without any injected dependencies.
See also:
How to inject Spring bean into JSF converter
As to the role of the converter itself, this is mandatory because HTML code is represented as one large string and HTTP request parameter values can only be represented as strings. Complex Java objects would otherwise be printed via Object#toString() like so com.example.Place#hashcode, making it unusable in the server side.
I found a better way, and probably more proper way to do get what I wanted. I was not completely sure how the converter works and how the value of the selected item gets passed back to the managed bean. I just declared a new Place object in my method, set the required values. Then I saw that it got passed to my managed bean
I got it to work like this in java EE with jsf 2.0. By making the converter a member of the backing bean. I instantiate this member using CDI but it should work the same with spring.
First the backing bean:
#ViewScoped
#ManagedBean
public class SomeView implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private SomeConverter converter;
public Converter getConverter() {
return converter;
}
}
And then this is the jsf xhtml:
<p:selectOneMenu id="someId" value="#{someView.value}" converter="#{someView.converter}">
<f:selectItems value="#{someView.values}" var="object" itemLabel="#{object.name}" />
</p:selectOneMenu>
Converter comes to play before updating your model bean. When user fill some input and this value is transferred to server first are updated your server side components and next conversion has happened. Converted values as saved in your bean (with method getAsObject) and before rendering the view values from beans are again converted to String because from user side everything is a string (then method getAsString is invoked).
In summary - Converter methods are the best place to change user input into your application logic, bean fields and in other way to convert your logic, bean fields into user friendly strings.
Due to your question and problem. You mean that SearchQueryService isn't available inside getAsObject method. Try to add an addnotation #Resource with proper name attribute and then it should be injected by your container.
I have a JSF form in which there is one field(textfield), value in textfield say profileId, which I need to use in many pages, so how can we store it in a session, and also how can we retrieve it as we need?
In simple words set a variable value in JSF session and also get it.
Bind it to a session scoped managed bean.
#ManagedBean
#SessionScoped
public class Profile {
private Long id;
// ...
}
with
<h:inputText value="#{profile.id}" />
You can access it in other beans by injecting it as #ManagedProperty.
#ManagedBean
#ViewScoped
public class OtherBean {
#ManagedProperty("#{profile}")
private Profile profile;
public void submit() {
System.out.println(profile.getId());
}
// ...
}
How can I refresh Spring configuration file without restarting my servlet container?
I am looking for a solution other than JRebel.
For those stumbling on this more recently -- the current and modern way to solve this problem is to use Spring Boot's Cloud Config.
Just add the #RefreshScope annotation on your refreshable beans and #EnableConfigServer on your main/configuration.
So, for example, this Controller class:
#RefreshScope
#RestController
class MessageRestController {
#Value("${message}")
private String message;
#RequestMapping("/message")
String getMessage() {
return this.message;
}
}
Will return the new value of your message String property for the /message endpoint when refresh is invoked on Spring Boot Actuator (via HTTP endpoint or JMX).
See the official Spring Guide for Centralized Configuration example for more implementation details.
Well, it can be useful to perform such a context reload while testing your app.
You can try the refresh method of one of the AbstractRefreshableApplicationContext class: it won't refresh your previously instanciated beans, but next call on the context will return refreshed beans.
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class ReloadSpringContext {
final static String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\"\n" +
" \t\"http://www.springframework.org/dtd/spring-beans.dtd\">\n";
final static String contextA =
"<beans><bean id=\"test\" class=\"java.lang.String\">\n" +
"\t\t<constructor-arg value=\"fromContextA\"/>\n" +
"</bean></beans>";
final static String contextB =
"<beans><bean id=\"test\" class=\"java.lang.String\">\n" +
"\t\t<constructor-arg value=\"fromContextB\"/>\n" +
"</bean></beans>";
public static void main(String[] args) throws IOException {
//create a single context file
final File contextFile = File.createTempFile("testSpringContext", ".xml");
//write the first context into it
FileUtils.writeStringToFile(contextFile, header + contextA);
//create a spring context
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
new String[]{contextFile.getPath()}
);
//echo the bean 'test' on stdout
System.out.println(context.getBean("test"));
//write the second context into it
FileUtils.writeStringToFile(contextFile, header + contextB);
//refresh the context
context.refresh();
//echo the bean 'test' on stdout
System.out.println(context.getBean("test"));
}
}
And you get this result
fromContextA
fromContextB
Another way to achieve this (and maybe a more simple one) is to use the Refreshable Bean feature of Spring 2.5+
With dynamic language (groovy, etc) and spring you can even change your bean behavior. Have a look to the spring reference for dynamic language:
24.3.1.2. Refreshable beans
One of the (if not the) most
compelling value adds of the dynamic
language support in Spring is the
'refreshable bean' feature.
A refreshable bean is a
dynamic-language-backed bean that with
a small amount of configuration, a
dynamic-language-backed bean can
monitor changes in its underlying
source file resource, and then reload
itself when the dynamic language
source file is changed (for example
when a developer edits and saves
changes to the file on the
filesystem).
I wouldn't recommend you to do that.
What do you expect to happen to singleton beans which their configuration modified? do you expect all singletons to reload? but some objects may hold references to that singletons.
See this post as well Automatic configuration reinitialization in Spring
You can take a look at this http://www.wuenschenswert.net/wunschdenken/archives/138 where once you change any thing in the properties file and save it the beans will be reloaded with the new values.