Web開発の過程で、データの相互作用は不可欠であり、クライアントとサーバー間でデータを渡すことができるように、インタラクティブデータの関連形式を指定する必要があります。通常、データ形式には2つのタイプがあります。1。xml。 2。Json。一般的に、JSONはデータの渡しに使用されます。この記事では、JSONとObjectsをJavaおよび関連する提案を変換する際に発生したいくつかの問題を紹介します。
まず、JSONの2つの概念があります。
JSONオブジェクト(JavaScriptオブジェクト表記、JavaScriptオブジェクト表記)。これはカスタムJavaScriptビットのようですが、それは構文として言語とプラットフォーム固有のものです。これは、通常、サーバー側(ブラウザー)にデータを渡すときにJSON形式を使用し、この形式はJavaScriptオブジェクトを表すために使用されることを意味します。 {"id":1、 "name": "kevin"}などの一連の「キー価値」で構成されています。 Javaに記載されているJSONオブジェクトは、実際にはJSonObjectクラスを指します。これは、通常、各サードパーティのJsonjarパッケージにこの名前にちなんで命名されています。異なるJARパッケージには、内部実装がわずかに異なります。
JSON文字列。 JSONオブジェクトとJSON文字列の間の変換は、シリアル化と脱派化のプロセスであり、Javaオブジェクトのシリアル化と脱介入のようなものです。ネットワーク内のデータ送信は、文字列またはバイナリストリームなどを介して実行されます。つまり、クライアント(ブラウザー)がJSON形式でデータを渡す必要がある場合、この時点で文字列がネットワークに渡され、もちろんサーバー側にはデータを受信した後も文字列(文字列タイプ)があります。 JSON文字列をJSONオブジェクトに変換し、次の操作を実行する必要がある場合があります(文字列タイプはjsonObjectタイプに変換されます)。
上記の2つの概念は、基本的にJSONのデータ形式、またはJSON構文とも呼ばれます。 JavaにはJSON用のJARパッケージがたくさんあります。最も「一般的に使用される」のは、「net.sf.json」が提供するJARパッケージです。この記事では、このピットパッケージに焦点を当てます。ピットですが、幅広いアプリケーションがあります。実際、Alibabaが最速のJSONパッケージであるGoogle's GSON、Jacksonであると主張するFastJsonなど、私たちが使用できる他の優れたJSONパッケージがあります。 「net.sf.json」パッケージを使用してみてください。落とし穴があるだけでなく、非常に古く、非常に古いので、アイデアのソースコードをダウンロードできません。 Mavenリポジトリは、2010年にバージョン2.4で停止したことを示しています。「net.sf.json」についてすでに知っている2つのバグと、これら2つのバグがどのように生成されたかについて説明しましょう。
JavaのJson Pitパッケージ-Net.sf.json
1. JavaオブジェクトがJSONオブジェクトを変換すると、GETから始まるすべてのメソッドが変換されます。
これは、次のJavaオブジェクトが利用可能であることを意味します。
パッケージSFJSON; Import Java.util.List;/***は2017/12/1にKevinによって作成されました。 */Public Class Student {private int id;プライベートリスト<long> courseids; public int getid(){return id; } public void setid(int id){this.id = id; } public list <long> getCourseIds(){return CourseIds; } public void setCourseids(list <long> courseids){this.courseids = courseids; } public string getSql(){//このクラスでSQLステートメントを取得するメソッドには、対応する属性フィールドリターン「これはSQLです」; }}学生オブジェクトをJSONオブジェクトに変換するとき、変換されたJSON形式が次のことを願っています。
{"id":1、 "CourseIds":[1、2、3]}ただし、 jsonobject json = jsonobject.fromobject(desute)の変換後の結果。 APIは次のとおりです。
言い換えれば、「net.sf.json」は、パブリックモディファイアがJavaオブジェクトで始まるから始まるメソッドを取得し、その接尾辞をJSONオブジェクトの「キー」として定義し、対応するキーの「値」として取得するメソッドの返品値を定義すると推測できます。パブリック修飾子GETから始まり、返品値があることから始まる方法であることに注意してください。
これは不合理な変換ルールだと思います。 Javaオブジェクトでメソッドを定義すると、この方法が「get」から始まり、返品値があるからといって、公開されますか?それとも、クライアントに返されるときにフロントエンドコンソールコンソール(ブラウザ)にさらされますか?著者は、この変換ルールを規定しています。私が考える大まかな理由は、あなたがそれをパブリック方法として定義し、それを取得するという名前の名前であるため、それを呼び出すクライアントがそれを取得する権利を持っているように、この方法を意図的に公開することです。しかし、私はまだこれは不合理だと思いますし、バグとして定義しています。私の実際のテストによれば、「net.sf.json」パッケージがこのルールに従って変換されるだけでなく、FastjsonとJacksonもこのルールに従って変換されるため、この方法を定義することは合理的ではないかもしれません。
構成された学生オブジェクトをjsonobject json = jsonobject.fromobject(desute)を介してJSONオブジェクトに変換します。そして、学生は上記のとおりです。この方法を入力した後、Object(Object、JSonConfig)から過負荷のメソッドが呼び出され続けます。このオーバーロードされた方法では、IntanceOFを使用して、変換されるオブジェクトオブジェクトが列挙、注釈、その他のタイプであるかどうかを判断します。これらの特別なタイプには、特別な判断方法があります。これは通常のJava Pojoオブジェクトです。そのため、_FromObject(Object、JSonConfig)に入り、この方法にいくつかの判断があり、最後にJSONオブジェクトはDefaultBeanProcessingを呼び出すことによって作成されます。この方法が重要であり、PropertyUtils.getPropertyDescriptors(BEAN)メソッドを介して「プロパティ記述子」を取得し続けます。実際、GETでメソッドを取得することです。これは、ここでプロパティデスプトールとしてカプセル化されています。この学生クラスは4を獲得します。つまり、GetClass、GetID、GetCourseids、GetSQL。
実際、PropertyDescriptorは詳細にカプセル化されており、すべての読み取りおよび書き込み方法が割り当てられています。
たとえば、このGetSQLメソッドは、上記の図のPropertyDescriptorに解析されています。以下は、このクラスを通じていくつかの方法を除外します。たとえば、GetClassメソッドはPojoのメソッドではないため、JSONオブジェクトに変換する必要はありません。 PropertyDescriptorはBeaninfo#getPropertyDescriptorsを介して取得され、Beaninfoは新しいIntroSpector(BeanClass、Null、use_all_beaninfo).getBeanInfo()を通じて取得されます。そして、最終的に次の方法に到達します。
private beaninfo getBeanInfo()throws introspectionException {…methoddescriptor mds [] = getTargetMethodinfo(); //この方法は、getPublicDeclaredMethodsを呼び出します。それは確かにパブリック方法を探していることがわかります、そして、待機やその他のプロパティデスプトールを含むすべてのパブリック方法PDS [] = getTargetPropertyInfo(); //特定のルールに従ってフィルタリングします。フィルタリングルールはすべてこの方法にあります。これは、パブリックモディファイアにGETプレフィックスと戻り値がある方法を選択するためです...net.sf.jsonのソースコードを簡単に分析しましたが、私が推測するように、特定のソースコードは比較的大きく、スペースが制限されており、自分で表示および追跡する必要があることがわかりました。
2。JavaオブジェクトをJSONオブジェクトに変換すると、リストに変換エラーが発生します<long>
タイトルは1つの文ではっきりと説明することはできません。この問題はバグであると確信しています。
これで、{"id":1、 "corseids":[1,2,3]}のjson文字列があり、上記の学生オブジェクトに変換する必要があります。 Typent intとList <long>の2つの属性フィールドが学生オブジェクトにあります。つまり、このJSON文字列は、対応するデータ型に変換する必要があります。
string json = "{/" id/":1、/" corseids/":[1,2,3]}"; sudent student =(desute)jsonobject.tobean(jsonobject.fromobject(json)、sustent.class); system.out.println(sudents.getCourseids()。上記の出力は真であるはずですが、残念ながらそれは間違っています。正確には、コンパイル時に長いですが、実行時には整数です。これは落とし穴であると言わなければならず、他の3つのJSONパッケージにはそのようなエラーがありません。だから私はそれがバグだと確信しています。このバグがnet.sf.jsonでどのように発生するかを見てみましょう。また、ソースコードを自分で比較して表示する必要があります。私は常にブレークポイントのデバッグを深めていましたが、net.sf.jsonが整数データを処理していたときに、この方法numberutils#createNumberを発見したことを発見しました。このクラスは、文字列からデータを抽出するときにデータ型を判断します。当初の意図は、その後の「L」または「L」がある場合に数値を処理することです。この観点から、最終結果は正しいはずです。
case 'l':case 'l':if(dec == null && exp == null &&(numeric.charat(0)== ' - ' && isdigits(numeric.substring(1))|| isdigits(numeric))){try {return createLong(numeric); } catch(numberformatexception var11){return createbiginteger(numeric); }} else {throw new NumberformateXception(str + "は有効な数字ではありません。"); }実際、これまでのところ、net.sf.jsonは、数字の後に識別子を介してデータ型を正確に判断しています。問題は、この値とそのデータ型を取得した後、jsonObjectに保存する必要があるという事実にあります。メソッドjsonutils#transformnumberは、ストレージプロセス中に存在します。この方法の存在は、少なくとも現在のビューでは純粋に贅沢です。
public static number transformnumber(number input){if(input instanceof float){return new double(input.toString()); } else if(input instance of short){return new Integer(input.intvalue()); } else if(input instance of byte){return new Integer(input.intvalue()); } else {if(input instanceof long){long max = new long(2147483647l); if(input.LongValue()<= max.LongValue()&& input.LongValue()> = -2147483648L){//元のタイプが長い場合でも、整数範囲内である限り、最終的には整数に変換されます。 new Integer(input.intvalue());を返します。 }} return input; }}上記のコードは、バイトやショートを含む長いタイプ(整数範囲内の長いタイプ)であるかどうかにかかわらず、犯人を明確に示しています。整数に変換されます。このコードの意味が何であるかわかりません。正確なデータ型は、数字の後の文字に基づいて決定する必要があり、正確なデータ型は後で再度変換する必要があります。これは、最初に言及されたバグにつながります。この問題はほとんど避けられないので、最良の方法はそれを使用しないことです。
これらの2つの落とし穴は偶然に発見されました。維持されていないnet.sf.jsonのJSONパッケージを使用しないことをお勧めします。さらに、net.sf.jsonパッケージは、JSON形式の検証ではそれほど厳格ではありません。そのような形式が「{"id":1、 "corseids": "[1,2,3]"} "である場合、例外は他の3つのパッケージでスローされますが、net.sf.jsonはそうではありません。
上記の記事では、JSONの落とし穴とJavaのオブジェクト転送について詳しく説明しています。これは私があなたと共有するすべてのコンテンツです。私はそれがあなたに参照を与えることができることを願っています、そしてあなたがwulin.comをもっとサポートできることを願っています。