1. ホーム
  2. validation

[解決済み] バリデーションエラーです。値が有効ではありません

2023-06-06 03:41:41

質問

p:selectOneMenuで問題が発生しました。何をやってもJSFがJPAエンティティのセッターを呼び出すことができません。JSFの検証はこのメッセージで失敗します。

form:location: バリデーションエラーです。値が有効ではありません

同じタイプの他のいくつかのクラス (たとえば、結合テーブル・クラス) でこれが機能していますが、このクラスがどうしてもうまくいきません。

この種の問題に対するトラブルシューティング/デバッグのヒントを投げられる人がいれば、それは非常に感謝されます。

ログ ステートメントを使用して、私は以下を確認しました。

  1. Conveter は正しく、非 null の値を返します。
  2. JPAエンティティにBean Validationがないのですが。
  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] 

どのように解決するのですか?

<ブロッククオート

バリデーションに失敗し、"form:location.Validationというメッセージが表示されます。Validation Error: 値は有効ではありません"。

このエラーは、選択された項目が、ネストされたすべての <f:selectItem(s)> タグで指定された値と一致しない場合に発生します。

改ざんやハッキングされたリクエストに対する安全策の一環として、JSF は利用可能なすべての選択項目の値を繰り返し、その値が 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 の代わりに @RequestScoped に変更することで、ほとんどの場合解決するはずです。のゲッターメソッドでビジネスロジックを実行しないことも確認してください。 <f:selectItem(s)> のゲッターメソッドでビジネスロジックを実行せず、代わりに @PostConstruct またはアクションイベント (リスナー) メソッドに格納します。もし特定のリクエストパラメータに依存しているのなら、明示的に @ViewScoped ビーンに格納するか、あるいは次のリクエストの際に例えば <f:param> . また 正しいビーンスコープを選択する方法は?
  2. が正しいことを確認します。 equals() メソッドが正しく実装されていることを確認します。これはすでに、標準的な Java の型である java.lang.String , java.lang.Number などがありますが、必ずしもカスタムオブジェクト/ビーン/エンタイトルに当てはまるとは限りません。また イコールコントラクトを実装する正しい方法 . すでに String を使用している場合、リクエストの文字エンコーディングが正しく設定されていることを確認してください。もし特殊文字が含まれていて、JSFが出力をUTF-8としてレンダリングし、入力を例えばISO-8859-1として解釈するように設定されている場合は、失敗します。a.o. も参照してください。 PrimeFaces入力コンポーネントで取得されたUnicode入力が破損する .
  3. カスタム Converter の動作をデバッグし、それに応じて修正します。ガイドラインについては コンバージョンエラー 'ヌルコンバーター'の値設定 を使用している場合 java.util.Date で利用可能な項目として <f:convertDateTime> のように、フルタイムの部分を忘れないようにパターン化してください。以下もご参照ください。 "バリデーションエラー。f:datetimeConverterのValue is not valid"エラーも参照してください。 .

こちらもご覧ください。


もし誰かがこの種の問題のトラブルシューティング/デバッグのヒントを投げられるなら、それは非常に感謝されるでしょう。

ここで明確で具体的な質問をしてください。あまりに広範な質問をしないようにしましょう;)