primefaces 的 bean 验证(JSR 303)不起作用
bean validation (JSR 303) for primefaces not working
我正在使用:
- Primefaces 6.1
- JSF:2.2.10
- javax.validation:1.1.0.Final
- 验证器实现:hibernate-validator 5.0.1.Final
- GAE:1.9.52
我使用来自以下后端 bean 的 CSV(客户端验证)示例:
https://www.primefaces.org/showcase/ui/csv/bean.xhtml
预期结果应该是:
我现在得到的是:
bean 验证不工作。
我在web.xml
中进行了以下配置
<context-param>
<param-name>primefaces.CLIENT_SIDE_VALIDATION</param-name>
<param-value>true</param-value>
</context-param>
很少有类似的帖子说需要将 jsf 降级到 2.2.2,我试过了,但还是不行。
现在 CSV 的解决方法是
- 使用基于demo的jsf标签验证
https://www.primefaces.org/showcase/ui/csv/basic.xhtml
例如:
<p:inputText id="age" value="#{beanValidationView.age}" label="Age">
<f:validateLongRange for="age" minimum="10" maximum="20" />
</p:inputText>
- 或者创建我自己的验证器
例如:
http://www.supermanhamuerto.com/doku.php?id=java:validatorinprimefaces
顺便说一句,我认为它与 GAE 无关。因为我尝试使用 Tomcat 9 的新动态 Web 项目,所以它给我的结果与下面的屏幕截图所示相同。
是不是我错过了任何配置或有不同版本的 jar 导致了这个问题?
通过放置依赖项(即 slf4j-jdk14、slf4j-api 和 jboss-el),Hibernate Validator 在 Tomcat 9 而不是 GAE 上工作。将日志级别配置为 FINER 后,记录器显示以下条目:
May 04, 2017 9:10:08 AM com.sun.faces.config.processor.ApplicationConfigProcessor addSystemEventListener
FINE: Subscribing for event javax.faces.event.PostConstructApplicationEvent and source javax.faces.application.Application using listener org.primefaces.extensions.application.PostConstructApplicationEventListener
May 04, 2017 9:10:08 AM com.sun.faces.config.processor.ApplicationConfigProcessor isBeanValidatorAvailable
FINE: java.lang.NoClassDefFoundError: javax.naming.InitialContext is a restricted class. Please see the Google App Engine developer's guide for more details.
java.lang.NoClassDefFoundError: javax.naming.InitialContext is a restricted class. Please see the Google App Engine developer's guide for more details.
at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:50)
at com.sun.faces.config.processor.ApplicationConfigProcessor.isBeanValidatorAvailable(ApplicationConfigProcessor.java:434)
at com.sun.faces.config.processor.ApplicationConfigProcessor.registerDefaultValidatorIds(ApplicationConfigProcessor.java:396)
at com.sun.faces.config.processor.ApplicationConfigProcessor.process(ApplicationConfigProcessor.java:353)
at com.sun.faces.config.processor.AbstractConfigProcessor.invokeNext(AbstractConfigProcessor.java:152)
at com.sun.faces.config.processor.LifecycleConfigProcessor.process(LifecycleConfigProcessor.java:137)
那是 "NoClassDefFoundError",但是登录为 FINE 级别而不是 Warning 和 return 更有意义的消息。那么不好。
所以我对 isBeanValidatorAvailable() 做了一个小改动,使其在 GAE 上运行
static boolean isBeanValidatorAvailable() {
boolean result = false;
final String beansValidationAvailabilityCacheKey =
"javax.faces.BEANS_VALIDATION_AVAILABLE";
Map<String,Object> appMap = FacesContext.getCurrentInstance().getExternalContext().getApplicationMap();
if (appMap.containsKey(beansValidationAvailabilityCacheKey)) {
result = (Boolean) appMap.get(beansValidationAvailabilityCacheKey);
} else {
try {
// Code for Google App Engine
ValidatorFactory validatorFactory = null;
try{
Object cachedObject=FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().get(BeanValidator.VALIDATOR_FACTORY_KEY);
if (cachedObject instanceof ValidatorFactory) {
validatorFactory=(ValidatorFactory)cachedObject;
} else {
validatorFactory=Validation.buildDefaultValidatorFactory();
}
}catch(ValidationException e) {
LOGGER.log(Level.WARNING, "Could not build a default Bean Validator factory",e);
}
if (null != validatorFactory) {
appMap.put(BeanValidator.VALIDATOR_FACTORY_KEY, validatorFactory);
result = true;
}
LOGGER.log(Level.FINE, "result=" +result +", validatorFactory=" +validatorFactory);
/* incompatible with Google App Engine
*
Thread.currentThread().getContextClassLoader().loadClass("javax.validation.MessageInterpolator");
// Check if the Implementation is available.
Object cachedObject = appMap.get(BeanValidator.VALIDATOR_FACTORY_KEY);
if(cachedObject instanceof ValidatorFactory) {
result = true;
} else {
Context initialContext = null;
try {
initialContext = new InitialContext();
} catch (NoClassDefFoundError nde) {
// on google app engine InitialContext is forbidden to use and GAE throws NoClassDefFoundError
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, nde.toString(), nde);
}
} catch (NamingException ne) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, ne.toString(), ne);
}
}
try {
Object validatorFactory = initialContext.lookup("java:comp/ValidatorFactory");
if (null != validatorFactory) {
appMap.put(BeanValidator.VALIDATOR_FACTORY_KEY, validatorFactory);
result = true;
}
} catch (NamingException root) {
if (LOGGER.isLoggable(Level.FINE)) {
String msg = "Could not build a default Bean Validator factory: "
+ root.getMessage();
LOGGER.fine(msg);
}
}
if (!result) {
try {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
appMap.put(BeanValidator.VALIDATOR_FACTORY_KEY, factory);
result = true;
} catch(Throwable throwable) {
}
}
}
*/
} catch (Throwable t) { // CNFE or ValidationException or any other
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Unable to load Beans Validation");
}
}
appMap.put(beansValidationAvailabilityCacheKey, result);
}
return result;
}
毕竟这个 JSR 303(Bean 验证)问题与 JSF2 上的 GAE 限制有关。
工作副本可以从 Google Drive.
获得
我遇到了同样的错误。
我通过升级 hibernate-validator
来修复它:
5.1.3.Final
到:
5.3.5.Final
我保留了 Primefaces 6.1。
我正在使用:
- Primefaces 6.1
- JSF:2.2.10
- javax.validation:1.1.0.Final
- 验证器实现:hibernate-validator 5.0.1.Final
- GAE:1.9.52
我使用来自以下后端 bean 的 CSV(客户端验证)示例: https://www.primefaces.org/showcase/ui/csv/bean.xhtml
预期结果应该是:
我现在得到的是:
bean 验证不工作。
我在web.xml
中进行了以下配置<context-param>
<param-name>primefaces.CLIENT_SIDE_VALIDATION</param-name>
<param-value>true</param-value>
</context-param>
很少有类似的帖子说需要将 jsf 降级到 2.2.2,我试过了,但还是不行。
现在 CSV 的解决方法是
- 使用基于demo的jsf标签验证
https://www.primefaces.org/showcase/ui/csv/basic.xhtml
例如:
<p:inputText id="age" value="#{beanValidationView.age}" label="Age">
<f:validateLongRange for="age" minimum="10" maximum="20" />
</p:inputText>
- 或者创建我自己的验证器
例如: http://www.supermanhamuerto.com/doku.php?id=java:validatorinprimefaces
顺便说一句,我认为它与 GAE 无关。因为我尝试使用 Tomcat 9 的新动态 Web 项目,所以它给我的结果与下面的屏幕截图所示相同。
是不是我错过了任何配置或有不同版本的 jar 导致了这个问题?
通过放置依赖项(即 slf4j-jdk14、slf4j-api 和 jboss-el),Hibernate Validator 在 Tomcat 9 而不是 GAE 上工作。将日志级别配置为 FINER 后,记录器显示以下条目:
May 04, 2017 9:10:08 AM com.sun.faces.config.processor.ApplicationConfigProcessor addSystemEventListener
FINE: Subscribing for event javax.faces.event.PostConstructApplicationEvent and source javax.faces.application.Application using listener org.primefaces.extensions.application.PostConstructApplicationEventListener
May 04, 2017 9:10:08 AM com.sun.faces.config.processor.ApplicationConfigProcessor isBeanValidatorAvailable
FINE: java.lang.NoClassDefFoundError: javax.naming.InitialContext is a restricted class. Please see the Google App Engine developer's guide for more details.
java.lang.NoClassDefFoundError: javax.naming.InitialContext is a restricted class. Please see the Google App Engine developer's guide for more details.
at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:50)
at com.sun.faces.config.processor.ApplicationConfigProcessor.isBeanValidatorAvailable(ApplicationConfigProcessor.java:434)
at com.sun.faces.config.processor.ApplicationConfigProcessor.registerDefaultValidatorIds(ApplicationConfigProcessor.java:396)
at com.sun.faces.config.processor.ApplicationConfigProcessor.process(ApplicationConfigProcessor.java:353)
at com.sun.faces.config.processor.AbstractConfigProcessor.invokeNext(AbstractConfigProcessor.java:152)
at com.sun.faces.config.processor.LifecycleConfigProcessor.process(LifecycleConfigProcessor.java:137)
那是 "NoClassDefFoundError",但是登录为 FINE 级别而不是 Warning 和 return 更有意义的消息。那么不好。
所以我对 isBeanValidatorAvailable() 做了一个小改动,使其在 GAE 上运行
static boolean isBeanValidatorAvailable() {
boolean result = false;
final String beansValidationAvailabilityCacheKey =
"javax.faces.BEANS_VALIDATION_AVAILABLE";
Map<String,Object> appMap = FacesContext.getCurrentInstance().getExternalContext().getApplicationMap();
if (appMap.containsKey(beansValidationAvailabilityCacheKey)) {
result = (Boolean) appMap.get(beansValidationAvailabilityCacheKey);
} else {
try {
// Code for Google App Engine
ValidatorFactory validatorFactory = null;
try{
Object cachedObject=FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().get(BeanValidator.VALIDATOR_FACTORY_KEY);
if (cachedObject instanceof ValidatorFactory) {
validatorFactory=(ValidatorFactory)cachedObject;
} else {
validatorFactory=Validation.buildDefaultValidatorFactory();
}
}catch(ValidationException e) {
LOGGER.log(Level.WARNING, "Could not build a default Bean Validator factory",e);
}
if (null != validatorFactory) {
appMap.put(BeanValidator.VALIDATOR_FACTORY_KEY, validatorFactory);
result = true;
}
LOGGER.log(Level.FINE, "result=" +result +", validatorFactory=" +validatorFactory);
/* incompatible with Google App Engine
*
Thread.currentThread().getContextClassLoader().loadClass("javax.validation.MessageInterpolator");
// Check if the Implementation is available.
Object cachedObject = appMap.get(BeanValidator.VALIDATOR_FACTORY_KEY);
if(cachedObject instanceof ValidatorFactory) {
result = true;
} else {
Context initialContext = null;
try {
initialContext = new InitialContext();
} catch (NoClassDefFoundError nde) {
// on google app engine InitialContext is forbidden to use and GAE throws NoClassDefFoundError
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, nde.toString(), nde);
}
} catch (NamingException ne) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, ne.toString(), ne);
}
}
try {
Object validatorFactory = initialContext.lookup("java:comp/ValidatorFactory");
if (null != validatorFactory) {
appMap.put(BeanValidator.VALIDATOR_FACTORY_KEY, validatorFactory);
result = true;
}
} catch (NamingException root) {
if (LOGGER.isLoggable(Level.FINE)) {
String msg = "Could not build a default Bean Validator factory: "
+ root.getMessage();
LOGGER.fine(msg);
}
}
if (!result) {
try {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
appMap.put(BeanValidator.VALIDATOR_FACTORY_KEY, factory);
result = true;
} catch(Throwable throwable) {
}
}
}
*/
} catch (Throwable t) { // CNFE or ValidationException or any other
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("Unable to load Beans Validation");
}
}
appMap.put(beansValidationAvailabilityCacheKey, result);
}
return result;
}
毕竟这个 JSR 303(Bean 验证)问题与 JSF2 上的 GAE 限制有关。
工作副本可以从 Google Drive.
获得我遇到了同样的错误。
我通过升级 hibernate-validator
来修复它:
5.1.3.Final
到:
5.3.5.Final
我保留了 Primefaces 6.1。