<o:validateBean>:将List<DemoData>变成List<String>?

问题描述 投票:0回答:1

我想使用 在类级别验证我的 bean。豆子是:

@Named
@ConversationScoped
public class ValidateClassLevelBean implements Serializable {
   ...
   @Inject
   private Conversation con;

   @Min(value = 2)
   @Max(value = 5)
   private int objectCount;

   @Valid
   private List<DemoData> listData;

   public String reInit() {
     if (!con.isTransient()) {con.end();}
     con.begin();

     listData = new ArrayList<>(objectCount);
     for (int i = 0; i < objectCount; i++) {
        listData.add(new DemoData("bbb", 3));
     }
    
    return "validProduct_2";
  }

  public String action() {
    for (DemoData d : listData) {
      logger.info("[listData: <" + d.toString() + ">]");
    }
    con.end();
    return "index";
  }
  ...
}

Facelet 看起来像这样:

 <h:form id="classLevelFormCustomCopier">
  ...
  <table>
   <ui:repeat value="#{validateClassLevelBean.listData}" var="data" varStatus="loop">
    <tr>
     <td>
      <h:inputText id="dataInput"
                   value="#{validateClassLevelBean.listData[loop.index]}"/>
     </td>
    </tr>
   </ui:repeat>
  </table>

  <h:commandButton value="submit" action="#{validateClassLevelBean.action}">
   <f:ajax execute="@form" render="@form"/>
  </h:commandButton>

  <o:validateBean value="#{validateClassLevelBean}"
                  validationGroups="de.test.wholebeanvalidation.validProduct.DemoDataGroup" />

DemoData
没什么特别的(存在
forClass
转换器):

@ValidDemoData(groups = DemoDataGroup.class)
public class DemoData implements Serializable {
  ...
  private String strData;
  private int intData;
  
  public DemoData() {
    this.strData ="";
    this.intData=0;
  }

  public DemoData(DemoData d) {
    this.strData =d.getStrData();
    this.intData = d.getIntData();
  }
  ...
}

验证约束注释:

@Constraint(validatedBy = { DemoDataValidator.class })
@Documented
@Target({ TYPE, METHOD, FIELD })
@Retention(RUNTIME)
public @interface ValidDemoData {
  String message() default "Invalid product";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
}

验证者:

public class DemoDataValidator implements ConstraintValidator<ValidDemoData, ValidateClassLevelBean> {
  ...
  @Override
  public void initialize(ValidDemoData constraintAnnotation) {
    logger.info("[ init ]");
  }

  @Override
  public boolean isValid(ValidateClassLevelBean value, ConstraintValidatorContext context) {
     ...
     return true;
  }
}

删除了

copier="..."
,例外情况是:

[2024-07-27T18:02:30.870+0200] [Payara 6.2024.1] [SCHWERWIEGEND] [] [org.omnifaces.taghandler.ValidateBean] [tid: _ThreadID=158 _ThreadName=http-thread-pool::http-listener-2(3)] [timeMillis: 1722096150870] [levelValue: 1000] [[
Exception occured while doing validation.
java.lang.ClassCastException: class java.lang.Class cannot be cast to class java.lang.reflect.ParameterizedType (java.lang.Class and java.lang.reflect.ParameterizedType are in module java.base of loader 'bootstrap')
at org.omnifaces.util.Reflection.setBeanPropertyWithDefaultValue(Reflection.java:410)
at org.omnifaces.util.Reflection.getBeanProperty(Reflection.java:397)
at org.omnifaces.util.Reflection.getBase(Reflection.java:336)
at org.omnifaces.util.Reflection.setBeanProperties(Reflection.java:314)
at org.omnifaces.taghandler.ValidateBean$3.invoke(ValidateBean.java:456)
at org.omnifaces.taghandler.ValidateBean$ValidateBeanCallback.run(ValidateBean.java:751)
at org.omnifaces.util.Events.lambda$wrap$1(Events.java:334)
at org.omnifaces.util.Events$4.afterPhase(Events.java:370)
at org.omnifaces.eventlistener.CallbackPhaseListener.afterPhase(CallbackPhaseListener.java:69)
at com.sun.faces.lifecycle.Phase.handleAfterPhase(Phase.java:148)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:78)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:159)
at jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:691)
at jakarta.faces.webapp.FacesServlet.service(FacesServlet.java:449)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1554)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:331)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:83)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:257)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:166)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:757)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:577)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:158)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:372)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:239)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217)
at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:190)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:535)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:515)
at java.base/java.lang.Thread.run(Thread.java:1583)
jsf omnifaces
1个回答
0
投票

存在 forClass 转换器

可观察到的问题最终不是由

<o:validateBean>
引起的。这是由于当前版本中泛型类型的擦除和 EL(那些
#{..}
的东西)无法处理它造成的。在
List
中设置新项目时,EL 不知道列表的通用类型是什么,因此采用默认值
String

您可以通过在输入组件上显式注册转换器来解决此问题,或者,正如您所发现的,通过使用普通数组而不是

List

<h:inputText id="dataInput"
             value="#{validateClassLevelBean.listData[loop.index]}"
             converter="yourDemoDataConverter" />
© www.soinside.com 2019 - 2024. All rights reserved.