0

重複の可能性:
selectOneMenu が ItemLabel をコンバーターに送信する理由

p:selectOneMenu非常に単純なエンティティを表す2 つの JSF ページがあります。

ListType エンティティ:

@Entity
@Table( name = "LISTTYPES" )
@NamedQueries
(
    {
        @NamedQuery( name  = "...",
                     query = "SELECT lty " +
                             "FROM ListType lty " +
                             "WHERE lty.name = :name "),
    }
)
public class ListType implements ClientDependent, Serializable
{
    @Id
    @Column( name = "LISTTYPE_ID" )
    private Long               id;

    @Basic( optional = false )
    @Column( name = "LIST_NO" )
    private Long               nbr;

    @Basic( optional = false )
    @Column( name = "LIST_NAME" )
    private String             name;

    @Column( name = "LIST_DESC" )
    private String             description;

    ...
}

MonitoringReason エンティティ:

@Entity
@Table( name = "MONITORINGREASONS" )
@NamedQueries
(
    {
        @NamedQuery( name  = "...",
                     query = "SELECT mtr " +
                             "FROM MonitoringReason mtr " +
                             "WHERE mtr.code = :code"),
    }
)
public class MonitoringReason implements Serializable
{
    @Id
    @Column( name = "MONITORINGREASON_ID" )
    private Long               id;

    @Basic( optional = false )
    @Column( name = "MONITORINGREASON_NO" )
    private String             code;

    @Basic( optional = false )
    @Column( name = "MONITORINGREASON_NAME" )
    private String             name;

    @Basic( optional = false )
    @Column( name = "MONITORINGREASON_DESC" )
    private String             description;

    ...
}

単純なエンティティ。両方のエンティティが正しく実装する equals + hashCode メソッドを省略したことに注意してください。

データの例を次に示します。

リスト型データ:

LISTTYPE_ID  LIST_NO  LIST_NAME           LIST_DESC
      1         3       'WL'        'Watch List'
      0         4       'RL'        'Restricted List'
      2         5       'Emb'       'Embargo'
      7         7       'NRL'       'Not Recommended List'
   5009        14       'GWL'       'Global Watch List'
   5010        15       'GRL'       'Global Restricted List'
   5011        16       'PIL'       'Permanent Insider List'

監視理由データ:

MONITORINGREASON_ID  MONITORINGREASON_NO  MONITORINGREASON_NAME  MONITORINGREASON_DESC
        3                   'Ah'           'Ad-Hoc'              'Ad-Hoc'
        6                   'Al'           'Autom. Liste'        'Automatische Liste'
        4                   'Be'           'Beobachtung'         'Beobachtung'
        7                   'CLC'          'Limit Changes'       'Limit Changes'
        1                   'Fus'          'Fusion'              'Fusion'
        5                   'Li'           'Liste'               'Liste'
        2                   'Res'          'Research'            'Research Unternehmen'

上記のエンティティに対する名前付きクエリは、コンバーターによってエンティティを検索するためのものです。

ListTypeConverter.java:

@Named
@RequestScoped
public class ListTypeConverter implements Converter
{
    @Inject
    @SeamLogger
    private Logger log;

    @Inject
    private SessionHelper sessionHelper;

    @Inject
    private ListTypeService listTypeService;

    @Override
    public Object getAsObject( FacesContext ctx, UIComponent comp, String identifier )
    {
        this.log.info( getClass().getSimpleName() + ".getAsObject: " + identifier );

        if ( identifier == null )
        {
            return null;
        }

        ListType listType = this.listTypeService.findByClientIdAndName( this.sessionHelper.getLoginUser().getClientId(), identifier );

        this.log.info( "Returning " + listType.getName() +  "!" );

        return listType;
    }

    ...
}

MonitoringReasonConverter.java:

@Named
@RequestScoped
public class MonitoringReasonConverter implements Converter
{
    @Inject
    @SeamLogger
    private Logger log;

    @Inject
    private SessionHelper sessionHelper;

    @Inject
    private MonitoringReasonService monitoringReasonService;

    @Override
    public Object getAsObject( FacesContext ctx, UIComponent comp, String identifier )
    {
        this.log.info( getClass().getSimpleName() + ".getAsObject: " + identifier );

        if ( identifier == null )
        {
            return null;
        }

        MonitoringReason monitoringReason = this.monitoringReasonService.findByClientIdAndCode( this.sessionHelper.getLoginUser().getClientId(), identifier );

        this.log.info( "Returning " + monitoringReason.getName() +  "!" );

        return monitoringReason;
    }

    ...
}

ご覧のとおり、ほとんどコピーに近い 2 つの単純な CDI コンバーターです。唯一の違いは、リスト タイプは名前でクエリされ、監視理由はコードでクエリされることです。(名前付きクエリを参照してください。正しいクエリがサービスによって呼び出されることを確認しました)

これらは、次のような JSF ページから使用されます。

<p:selectOneMenu id="list-type"
                 value="#{complianceCaseManager.selectedListType}"
                 converter="#{listTypeConverter}">
    <f:selectItems value="#{listTypeManager.selectableListTypes}"
                   var="ltp"
                   itemValue="#{ltp}"
                   itemLabel="#{ltp.description}" />
    <p:ajax process="@this" update="@form" />
</p:selectOneMenu>

<p:selectOneMenu id="monitoring-reason"
                 value="#{complianceCaseManager.selectedMonitoringReason}"
                 converter="#{monitoringReasonConverter}">
    <f:selectItems value="#{monitoringReasonManager.selectableMonitoringReasons}"
                   var="mtr"
                   itemValue="#{mtr}"
                   itemLabel="#{mtr.name}" />
    <p:ajax process="@this" update="@form" />
</p:selectOneMenu>

OK、ここも同じ、基本的に同じコピーされたコードです。唯一の違いは、リスト タイプがUI ラベルとしてitemLabel="#{ltp.description}"使用され、監視理由itemLabel="#{mtr.name}"が UI ラベルとして使用されることです。

今起こっていることは、私が期待していたことではありません。

リスト・タイプ・コンバーターモニター理由コンバーターの両方が、JSF から ID として名前を取得します。これは、リスト型コンバーターでは名前の付いたクエリを使用してそれぞれのエンティティを検索するため、問題にはなりません。これは、選択の変更を実行するときに発生します。

2012-12-18 22:51:23,923 [http-thread-pool-8181(5)] INFO  de.company.project.ListTypeConverter     - ListTypeConverter.getAsObject: RL
2012-12-18 22:51:23,927 [http-thread-pool-8181(5)] INFO  de.company.project.ListTypeConverter     - Returning RL!

ただし、監視理由の選択を使用すると、次のログが記録されます。

2012-12-18 22:52:02,091 [http-thread-pool-8181(2)] INFO  de.company.project.MonitoringReasonConverter     - MonitoringReasonConverter.getAsObject: Fusion
2012-12-18 22:52:02,100 [http-thread-pool-8181(2)] ERROR de.company.project.MonitoringReasonService       - Monitoring reason not found for client ID = 1 with code Fusion
javax.persistence.NoResultException: getSingleResult() did not retrieve any entities.
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.throwNoResultException(EJBQueryImpl.java:1307)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getSingleResult(EJBQueryImpl.java:778)
    at de.company.project.MonitoringReasonService.findByClientIdAndCode(MonitoringReasonService.java:92)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
    at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
    at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5388)
    at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:619)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
    at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:42)
    at sun.reflect.GeneratedMethodAccessor7832.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
    at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
    at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:144)
    at sun.reflect.GeneratedMethodAccessor7831.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
    at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
    at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:370)
    at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5360)
    at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5348)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:214)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:89)
    at $Proxy2626.findByClientIdAndCode(Unknown Source)
    at de.company.project.__EJB31_Generated__MonitoringReasonService__Intf____Bean__.findByClientIdAndCode(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:267)
    at org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:52)
    at org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:137)
    at org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:263)
    at org.jboss.weld.bean.proxy.EnterpriseBeanProxyMethodHandler.invoke(EnterpriseBeanProxyMethodHandler.java:110)
    at org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
    at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105)
    at de.company.project.MonitoringReasonService$Proxy$_$$_Weld$Proxy$.findByClientIdAndCode(MonitoringReasonService$Proxy$_$$_Weld$Proxy$.java)
    at de.company.project.MonitoringReasonConverter.getAsObject(MonitoringReasonConverter.java:63)
    at de.company.project.MonitoringReasonConverter$Proxy$_$$_WeldClientProxy.getAsObject(MonitoringReasonConverter$Proxy$_$$_WeldClientProxy.java)
    at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInputRenderer.java:171)
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectOneValue(MenuRenderer.java:201)
    at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:318)
    at org.primefaces.component.selectonemenu.SelectOneMenuRenderer.getConvertedValue(SelectOneMenuRenderer.java:55)
    at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
    .
    .
    .

質問:

  1. 変換プロセスでname プロパティが両方に使用されるのはなぜですか?
  2. name プロパティが getAsObject メソッドの文字列値に使用されるべきであり、(私が常に想定していたように) に渡されるプロパティではないことを決定するものは何itemLabel="..."ですか? どうやってコントロールするの??
  3. その情報は JSF 仕様のどこに隠されていますか? (ここでオーバーライドを行っている PrimeFaces でない場合)
4

2 に答える 2

1

これはConverterの問題になると思います。これに似た質問を見つけました。これを確認すると役立つ場合があります。selectOneMenu が ItemLabel をコンバーターに送信する理由

于 2012-12-19T08:13:33.200 に答える
0

答えは最終的に、私のコンバーターのメソッドが受け取るgetAsString()文字列を定義するということです。getAsObject私は常に、値は JSF によって決定されると想定していました。たとえば、itemLabel="..."そうではありません。

それについて考えると、私はこのように理にかなっていますが、1.5年以上のJSFの読み取りとプログラミングでこの情報を見逃していたことにかなりショックを受けています...

于 2012-12-19T09:51:16.023 に答える