ActionScript 3のSOAP Webサービスに「Null」(本当の姓!)を渡す方法


4636

姓がNullの従業員がいます。その姓が検索語として使用されると、従業員の検索アプリケーションが強制終了されます(今ではかなり頻繁に使用されています)。受け取ったエラー(Fiddlerに感謝!)は次のとおりです。

<soapenv:Fault>
   <faultcode>soapenv:Server.userException</faultcode>
   <faultstring>coldfusion.xml.rpc.CFCInvocationException: [coldfusion.runtime.MissingArgumentException : The SEARCHSTRING parameter to the getFacultyNames function is required but was not passed in.]</faultstring>

かわいいでしょ?

パラメータタイプはstringです。

使っています:

  • WSDLSOAP
  • フレックス3.5
  • ActionScript 3
  • ColdFusion 8

このエラー、ColdFusionページからオブジェクトとしてWebサービスを呼び出す場合に発生しません


6
特定の問題についてはそれほど役に立たないかもしれませんが、SOAP 1.2ではnull可能値が許可されています。w3.org
TR / 2001 /

6
デイブ・ヌルが関係しているような気がします。
ジョージギブソン

2
少なくとも、チャックノリスは関与していません。コードで彼から離れる理由は次のとおり
SDsolar

42
従業員は名前を変更することを検討しましたか?
Tatranskymedved 2017年

11
彼は本当にポインター犬を購入し、彼をNullPointerと呼ぶことを検討すべきです。
Antonio Alvarez

回答:


1109

追跡する

最初は、これは強制nullされてい"null"て、テスト"null" == nullに合格する強制バグだと思っていました。そうではありません。私は近くにいたが、とても、とても間違っていた。申し訳ありません!

私はそれ以来、wonderfl.netいじくり回したり、のコードをたどったりしてきましたmx.rpc.xml.*XMLEncoder(3.5のソースの)1795行目でsetValue、すべてのXMLEncodingは次のように要約されます。

currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));

これは本質的に同じです:

currentChild.appendChild("null");

私の元のフィドルによると、このコードは空のXML要素を返します。しかし、なぜ?

原因

バグレポートFLEX-33664に関するコメント投稿者 Justin Mcleanによると、以下が原因です(これを確認する私のフィドルの最後の2つのテストを参照してください)。

var thisIsNotNull:XML = <root>null</root>;
if(thisIsNotNull == null){
    // always branches here, as (thisIsNotNull == null) strangely returns true
    // despite the fact that thisIsNotNull is a valid instance of type XML
}

場合はcurrentChild.appendChild、文字列渡され"null"、テキストを持つルートXML要素とその最初の変換をnullした後、ヌルリテラルに対して、その要素をテストします。これは弱い等価テストであるため、nullを含むXMLがnull型に強制変換されるか、null型が文字列 "null"を含むルートxml要素に強制変換され、テストは間違いなく失敗するはずです。1つの修正は、XML(または実際には何でも)の「n​​ull値」をチェックするときに常に厳密な等価テストを使用することです。

解決

私が考えることができる唯一の合理的な回避策は、ActionScriptのすべてのいまいましいバージョンでこのバグを修正する前に、フィールドを「null」でテストし、CDATA値としてエスケープすることです

CDATA値は、テキスト値全体を変更する最も適切な方法であり、そうしないとエンコード/デコードの問題が発生します。たとえば、16進エンコーディングは個々の文字を対象としています。要素のテキスト全体をエスケープする場合は、CDATA値が推奨されます。これの最大の理由は、人間の可読性を維持することです。


298

XKCDノートボビーテーブルのウェブサイトは、ユーザデータの不適切な解釈(この場合は、文字列「NULL」)SQL内を含む様々な言語で照会避けるための良いアドバイスがあるColdFusionを

これが問題の原因であることは質問から明らかではありません。最初の回答(パラメーターを構造体に埋め込む)へのコメントに記載されている解決策を考えると、それは別の問題である可能性があります。


239

問題はFlexのSOAPエンコーダーにある可能性があります。FlexアプリケーションでSOAPエンコーダーを拡張し、プログラムをデバッグして、null値がどのように処理されるかを確認してください。

私の推測では、NaN(Not a Number)として渡されます。これは、SOAPメッセージの非整列化プロセスを混乱させることがあります(特に、JBoss 5サーバーで...)。SOAPエンコーダーを拡張し、NaNの処理方法を明示的に確認したことを覚えています。


12
name = "Null"はもちろん便利ですが、それがどのようにNaNに関係するべきかわかりません。
eckes

129

@ doc_180は、数字に焦点を当てていることを除いて、正しい概念を持っていましたが、元のポスターには文字列に関する問題がありました。

解決策は、mx.rpc.xml.XMLEncoderファイルを変更することです。これは121行目です。

    if (content != null)
        result += content;

(Flex 4.5.1 SDKを確認しました。他のバージョンでは行番号が異なる場合があります。)

基本的に、 'content is null'で検証が失敗するため、引数が発信SOAPパケットに追加されません。したがって、欠落しているパラメーターエラーが発生します。

検証を削除するには、このクラスを拡張する必要があります。次に、チェーンに大きな雪だるまがあります。SOAPEncoderを変更して、変更したXMLEncoderを使用します。次に、Operationを変更して、変更したSOAPEncoderを使用し、WebServiceを変更して、代替のOperationクラスを使用します。

数時間を費やしましたが、次に進む必要があります。おそらく1〜2日かかります。

XMLEncoderの行を修正して、独自のクラスを使用するためにサルのパッチ適用できる場合があります。

また、ColdFusionでRemoteObject / AMFを使用するように切り替えた場合、問題なくnullが渡されることも追加します。


2013年11月16日更新

RemoteObject / AMFに関する私の最後のコメントに、もう1つ最近追加しました。ColdFusion 10を使用している場合。次に、オブジェクトにnull値を持つプロパティがサーバー側オブジェクトから削除されます。したがって、アクセスする前にプロパティの存在を確認する必要があります。そうしないと、ランタイムエラーが発生します。

このように確認してください:

<cfif (structKeyExists(arguments.myObject,'propertyName')>
 <!--- no property code --->
<cfelse>
 <!--- handle property  normally --->
</cfif>

これは、ColdFusion 9からの動作の変更です。nullプロパティは空の文字列になります。


2013年12月6日を編集

nullがどのように扱われるかについての質問があったので、文字列「null」が予約語nullにどのように関係するかを示す簡単なサンプルアプリケーションを次に示します。

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="application1_initializeHandler(event)">
    <fx:Script>
        <![CDATA[
            import mx.events.FlexEvent;

            protected function application1_initializeHandler(event:FlexEvent):void
            {
                var s :String = "null";
                if(s != null){
                    trace('null string is not equal to null reserved word using the != condition');
                } else {
                    trace('null string is equal to null reserved word using the != condition');
                }

                if(s == null){
                    trace('null string is equal to null reserved word using the == condition');
                } else {
                    trace('null string is not equal to null reserved word using the == condition');
                }

                if(s === null){
                    trace('null string is equal to null reserved word using the === condition');
                } else {
                    trace('null string is not equal to null reserved word using the === condition');
                }
            }
        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
</s:Application>

トレース出力は次のとおりです。

!=条件を使用したnull文字列はnull予約語と等しくありません

==条件を使用したnull文字列はnull予約語と等しくありません

===条件を使用したnull文字列はnull予約語と等しくありません


8
@ Reboog711従業員の姓は文字列「Null」であり、「私の名前はPat Nullです」のように答えると、従業員の姓を渡すことができません。あなたが答えるのは、Ben Burnsによって説明されているように、appendChild()メソッドによって「Null」がnullの言語概念に不適切に強制されているという事実を隠すだけです。その結果、システムはヌル氏またはヌル氏に対処することができません。
Maxx Daymon 2013年

2
@MaxxDaymon私の答えが実際に何であるかを誤解していると思います。それは解決策を提示しません。むしろ問題が発生する理由の説明; また、Flexフレームワークの関連コードを引用します。私の最近の編集はおそらく見当違いです。別のアプローチについて説明しているため、元の質問とは直接関係ありません。
JeffryHouser 2013年

1
あなたは正しい軌道に乗っていますcontentが、コードのその時点では文字列"null"であり、 "null" == nullはfalseを返すため、テストは意図したとおりに動作します。代わりに、問題はXML.appendChildが文字列引数を処理する方法と、文字列「null」のみを含むルートXML要素をリテラルに強制変換できる方法の組み合わせであると考えていますnull
Ben Burns

@ Reboog711私のフィドルを見てください。"null"!= null`を返すことtrueは、ここで望ましい動作です。逆のことが起こった場合、これは文字列「null」をエンコードプロセスから破棄し、それが実際に問題の原因になります。ただし、このテストは成功したため、強制バグによりXML.appendChildが破棄するまで、エンコーダーは続行します。
Ben Burns

4
心配ない。実際の問題を確認したい場合はvar xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s);、コードサンプルに追加してください。
Ben Burns

65

すべての文字を対応する16進エンティティに変換します。この場合、Nullに変換されます&#4E;&#75;&#6C;&#6C;


41
これを行わないでください。CDATAは、テキストのブロック全体をエスケープする必要がある場合に使用するために作成されました。
Ben Burns

4
私は間違っている可能性がありますが、あなたの解決策がそれがどのように機能することになっているのかではなかったからといって、反対票を投じるとは思いません。また、投稿されたさまざまなソリューションから明らかなように、1つの明白な方法がないため、問題はヒューリスティックなソリューションを必要とすることに留意する必要があります。最後に、私はCFを知らないことを念頭に置いて、デコーダーは<message> <![CDATA [NULL]]> </ message>の内部テキストを<message> NULL </の内部テキストと同じにしないでしょう。メッセージ>?もしそうなら、CDATAは本当に本当にソリューションですか?
doogle 2013

7
これはアンチパターンなので、私は反対票を投じました。この場合のバグはCFではなく、ActionScriptにあります。しかし、それでもあなたは良い点を上げます。CDATAエンコーディングのフィドルにテストを追加します。
Ben Burns

51

文字列化nullの値のActionScriptは、文字列を与えます"NULL"。私の疑いは、文字列を"NULL"としてデコードすることをお勧めします。そのため、nullここで見られるような破損が発生します。おそらく、nullオブジェクトを渡してデータベースに文字列を取得していたので、望まないときに(そのようなバグも必ず確認してください)。


はい、多くの可能性があり、絞り込むにはさらにデバッグが必要になります。1)ここで使用されるWSDLは、文字列値としての「NULL」と実際のnull(または省略)値を区別するのに十分表現力がありますか?2)その場合、クライアントは姓を正しくエンコードしている(nullリテラルではなく文字列として)か。3)その場合、サービスは "NULL"を文字列として適切に解釈しているか、それともnull値に強制変換しているか。
pimlottc 2013年

39

ハックとして、クライアント側で特別な処理を行うことを検討できます。たとえば、「Null」文字列を発生しないもの(XXNULLXXなど)に変換し、サーバーで再び変換します。

それはきれいではありませんが、そのような境界ケースの問題を解決する可能性があります。


32
XXNULLXXも名前にすることができます。あなたは知りません。多分インドネシアの人々は姓を持たず、必要に応じて姓としてXXXの変種を使用します。
gb。

3
同じ概念ですが、データベース内のすべての名前を更新し、その前にいくつかの文字(1Null、1Smith)を付けます。クライアントでその文字を削除します。もちろん、これはReboogのソリューションよりもダニの仕事かもしれません。
bobpaul 2013年

14
@BenBurnsええ、でも子供に名前を付けたいとしたらどうし&#78;&#117;&#108;&#108;ますか?
サイレン

@サイレンそれは問題ではありません。私の名前が「<&quot;>」の場合、「&lt;&amp; quot;&gt;」として適切にエスケープされることを期待していますが、言うまでもありません。実際の問題は、名前のブラックリストを使用するかのように動作するアプリケーションにあります。
リスター氏2017

30

そうですね、SOAPエンコーダーのFlexの実装では、null値が誤ってシリアル化されているようです。それらをString Nullとしてシリアル化することは良い解決策ではないようです。正式に正しいバージョンは、次のようにnull値を渡すようです。

<childtag2 xsi:nil="true" />

したがって、「Null」の値は有効な文字列に他なりません。これはまさにあなたが探しているものです。

これをApache Flexで修正するのはそれほど難しいことではないでしょう。Jiraの問題を開くか、apache-flexメーリングリストの担当者に連絡することをお勧めします。ただし、これはクライアント側のみを修正します。ColdFusionがこの方法でエンコードされたnull値を処理できるかどうかはわかりません。

Radu Cotescuのブログ投稿「soapUIリクエストでnull値を送信する方法」も参照してください。


6
ここには良い情報があるので、私は反対票を投じませんが、コメントする価値があると考えました。デフォルトでは、XMLEncoder.asは、要素にnull設定することにより、実際にtrue 値を適切にエンコードしますxsi:nil="true"。問題は実際には、ActionScript XMLタイプ自体(エンコーダーではない)がstringを処理する方法にあるよう"null"です。
ベンバーンズ

22

それはその場しのぎだが、の最小長があると仮定するとSEARCHSTRING2つの文字は、例えば、第二の文字でのパラメータ、代わりに二つのパラメータとして渡し:とデータベースにクエリを実行する場合、それらは一緒にバック。substringSEARCHSTRINGSEARCHSTRING1 ("Nu")SEARCHSTRING2 ("ll"). Concatenate


32
CDATAがXML仕様に追加され、これらのタイプのクラッジを回避しました。
ベンバーンズ

8
CDATAで「Null」をエスケープする必要はありません。XMLにはnullキーワードなどはありません。
eckes

6
@eckesに同意します。なぜCDATAのこのような話がすべてあるのか理解できません。CDATAは、XMLで特別な意味を持つ文字をエスケープする場合にのみ役立ちます。いずれ:nulXMLで特別な意味を持っていません。「NULL」および「<![CDATA [NULL]]>」は、XMLパーサーと同じです。
jasonkarns

9
@jasonkarns -私はそこにいることを100%に同意する必要があり、文字列/テキストノードについて何も特別なことNULLはなく、知識をひけらかすこと、<blah>null</blah>および<blah><![CDATA[null]]>XMLパーサに同じではありません。それら同じ結果生成するはずですが、それらを処理するための論理フローは異なります。フレックスXML実装のバグの回避策として利用しているのはこの影響です。テキストの可読性を維持し、他のパーサーに副作用がないため、他のアプローチよりもこれを推奨します。
Ben Burns
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.