83

ap:selectOneMenuに問題があります。何をしても、JSFにJPAエンティティのセッターを呼び出させることができません。JSF検証は次のメッセージで失敗します:

form:location:検証エラー:値が無効です

私はこれを同じタイプの他のいくつかのクラス(つまり、結合テーブルクラス)で動作させていますが、私の人生ではこれを動作させることはできません。

誰かがこの種の問題のトラブルシューティング/デバッグのヒントを投げることができれば、それは大いにありがたいです。

ログステートメントを使用して、次のことを確認しました。

  1. Conveter正しい非null値を返しています。
  2. JPAエンティティにBeanValidationがありません。
  3. セッターsetLocation(Location location)が呼び出されることはありません。

これは私ができる最も簡単な例であり、単純に機能しません。

<h:body>
    <h:form id="form">
        <p:messages id="messages" autoUpdate="true" />
        <p:selectOneMenu id="location" value="#{locationStockList.selected.location}" converter="locationConverter">
            <p:ajax event="change" update=":form:lblLocation"/>
            <f:selectItems value="#{locationStockList.locationSelection}"/>
        </p:selectOneMenu>
    </h:form>
</h:body>

コンバータ:

@FacesConverter(forClass=Location.class, value="locationConverter")
public class LocationConverter implements Converter, Serializable {
    private static final Logger logger = Logger.getLogger(LocationConverter.class.getName());

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value.isEmpty())
            return null;
        try {
            Long id = Long.parseLong(value);
            Location location = ((LocationManagedBean) context.getApplication().getELResolver().getValue(context.getELContext(), null, "location")).find(id);
            logger.log(Level.SEVERE, "Converted {0} to {1}" , new Object[] {value, location});
            return location;
        } catch (NumberFormatException e) {
            return new Location();
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value == null || value.toString().isEmpty() || !(value instanceof Location))
            return "";
        return String.valueOf(((Location) value).getId());
    }    
}

コンソール出力:

// Getter method
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0] 
// Session Bean
INFO: Finding ejb.locations.Location with id=3 
// Session Bean
INFO: ### Returning : ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3] 
// Converter
SEVERE: Converted 3 to ejb.locations.Location[id=3, name=mdmd, latitude=4.5, longitude=2.3] 
// Getter method -> Where did my selected Location go ??
INFO: Current value=ejb.locations.Location[id=null, name=null, latitude=0.0, longitude=0.0] 
4

3 に答える 3

147

「form:location:Validation Error:Valueisnotvalid」というメッセージで検証が失敗します

<f:selectItem(s)> このエラーは、選択されたアイテムが、フォーム送信要求の処理中にネストされたタグによって指定された使用可能な選択アイテムの値のいずれとも一致しないことを意味します。

改ざん/ハッキングされたリクエストに対する保護の一環として、JSFは利用可能なすべての選択されたアイテムの値を繰り返し、少なくとも1つの利用可能なアイテムの値selectedItem.equals(availableItem) が返されるかどうかをテストします。true一致するアイテムの値が1つもない場合は、まさにこの検証エラーが発生します。

このプロセスは基本的に以下のようにカバーされており、以下でbean.getAvailableItems()定義されているように、利用可能な選択アイテムのリスト全体を架空で表しています<f:selectItem(s)>

String submittedValue = request.getParameter(component.getClientId());
Converter converter = component.getConverter();
Object selectedItem = (converter != null) ? converter.getAsObject(context, component, submittedValue) : submittedValue;

boolean valid = false;

for (Object availableItem : bean.getAvailableItems()) {
    if (selectedItem.equals(availableItem)) {
        valid = true;
        break;
    }
}

if (!valid) {
    throw new ValidatorException("Validation Error: Value is not valid");
}

したがって、上記の論理に基づいて、この問題には少なくとも次の原因が論理的に発生する可能性があります。

  1. 選択したアイテムが利用可能なアイテムのリストにありません。
  2. equals()選択したアイテムを表すクラスのメソッドが欠落しているか、壊れています。
  3. カスタムConverterが含まれている場合、それはで間違ったオブジェクトを返しましたgetAsObject()。おそらくそれもnullです。

それを解決するには:

  1. 特に複数のカスケードメニューの場合は、後続のリクエスト中にまったく同じリストが保持されるようにしてください。@ViewScoped代わりにBeanを作成@RequestScopedすると、ほとんどの場合修正されます。<f:selectItem(s)>また、のgetterメソッドではなく、@PostConstructまたはアクションイベント(リスナー)メソッドでビジネスロジックを実行するようにしてください。特定のリクエストパラメータに依存している場合は、それらを@ViewScopedBeanに明示的に格納するか、たとえば、以降のリクエストでそれらを再渡す必要があります<f:param>適切なBeanスコープを選択する方法も参照してください。
  2. equals()メソッドが正しく実装されていることを確認してください。java.lang.Stringこれは、、などの標準のJavaタイプですでに正しく行われていますjava.lang.Numberが、必ずしもカスタムオブジェクト/Bean/エンティティで行われているとは限りません。等しいコントラクトを実装する正しい方法も参照してください。すでにを使用している場合はString、要求文字エンコードが正しく構成されていることを確認してください。特殊文字が含まれていて、JSFが出力をUTF-8としてレンダリングするように構成されているが、入力をISO-8859-1などとして解釈する場合、失敗します。PrimeFaces入力コンポーネントを介して取得されたUnicode入力が破損することも参照してください。
  3. カスタムのアクションをデバッグ/ログに記録し、Converterそれに応じて修正します。ガイドラインについては、「null Converter」の変換エラー設定値も参照してください。で使用java.util.Date可能なアイテムとして使用し<f:convertDateTime>ている場合は、パターンのフルタイム部分を忘れないようにしてください。f:datetimeConverterの「検証エラー:値が無効です」エラーも参照してください。

参照:


誰かがこの種の問題のトラブルシューティング/デバッグのヒントを投げることができれば、それは大いにありがたいです。

ここで明確で具体的な質問をしてください。広すぎる質問をしないでください;)

于 2012-01-30T19:35:50.590 に答える
2

私の場合、正しいget/setメソッドを実装するのを忘れていました。これは、開発中に多くの属性を変更したために発生しました。

適切なgetメソッドがないと、JSFは選択したアイテムを復元できず、BalusCが回答のアイテム1で言ったことを実行します。

1。選択したアイテムが利用可能なアイテムのリストにありません。これは、使用可能なアイテムのリストが、後続のリクエストで適切に再初期化されないリクエストスコープのBeanによって提供される場合、または何らかの方法で別のリストを返す原因となるgetterメソッド内でビジネスジョブを誤って実行している場合に発生する可能性があります。

于 2015-02-12T15:18:15.897 に答える
1

これは、コンバーターの問題またはDTOの問題である可能性があります。オブジェクトDTOにhashCode()メソッドとequals()メソッドを追加して、これを解決してみてください。上記のシナリオでは、ここで「DTO」として示されるLocationオブジェクトクラス内でこれらのメソッドを生成できます。

例:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (id ^ (id >>> 32));
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Location other = (Location) obj;
    if (id != other.id)
        return false;
    return true;
}
  • 上記の例は、「long」タイプの「id」用であることに注意してください。
于 2018-08-16T06:00:35.200 に答える