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


80

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] 

回答:


143

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

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

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

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

参照:


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

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


@BalusC:このequalsチェックが行われるのは、mojarraコードの正確な場所です。私の状況は少し複雑です。ユーザーが複雑な無線レイアウトを使用できるようにする独自のカスタムコンポーネントを作成します。ラジオグループが1つしかない場合(カスタムコンポーネントのすぐ下にあるf:selectItems)は正常に機能します。ただし、レイアウトがより複雑になると(複数のラジオグループ、それぞれに独自のf:selectItemsがありますが、すべて同じ選択を共有します)、ui:repeat内にf:selectItemsを含める必要があり、ui:repeatはカスタムコンポーネントの下にあります。その後、この問題に遭遇しました。これを処理するクロサギのコードを見たい
Thang Pham

また、私のf:selectItemsは文字列型なので、これは変換の問題ではないと確信しています。検証フェーズでf:selectItemsのリストがないため、これが原因だと思います。
タンファム2012年

f:paramを使用して状態をマネージドBeanに送信し、「初期状態」を再作成できるようにする方法について詳しく説明していただけますか?ありがとう。
–AgustíSánchez 2014

1
同様のエラーが発生しています。SelectItemsConverterを使用していますが、このコンポーネントは無効なフィールドセット内にあるため、同様に無効になっています。それは既知の動作ですか?
ギルベルト2014

表示するアイテムに列挙型を使用していて、バッキングBeanがBeanの値を設定するための文字列型を持ち、コンバーターを使用していない場合、同じエラーが発生します。それが私がここにたどり着いた方法です。
フィリッププーテンビラ2015

2

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

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

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


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」用であることに注意してください。

受け入れられ、高度upvoted答えで#2に記載のように
Kukeltje
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.