JSON با Jackson، (بخش دوم) Stream Method

در این مقاله سه روش مختلف تولید و خواندن JSON با Jackson را معرفی میکنیم. یک مثال با روش اول برنامهنویسی کرده و در نهایت به این سوال میپردازیم که «Streaming API برای چه موقعیتی مناسبتر است؟»
جدول زیر سه روش مذکور و کلاسهای اصلی مورد استفاده در هر روش را نشان می دهد.
نام روش | کلاس اصلی | مشابه XML |
Streaming API | com.fasterxml.jackson.core.JsonParser com.fasterxml.jackson.core.JsonGenerator |
StAX API |
Tree Model | com.fasterxml.jackson.databind.ObjectMapper
com.fasterxml.jackson.TreeNode |
XML DOM |
Data Binding | com.fasterxml.jackson.databind.ObjectMapper | JAXB |
روش Streaming API روش پایه، یا سطح پایین تعامل با JSON است. دو روش دیگر Tree Model و Data Binding از Streaming API استفاده میکنند و به آن متکی هستند ولی کار با JSON را تسهیل کردهاند.
Streaming API
برای تولید JSON کلاس JsonGenerator و برای خواندن آن JsonParser مورد استفاده قرار میگیرد. این دو توسط کلاسی به اسم com.fasterxml.jackson.core.JsonFactory تولید میشوند. سپس با استفاده از متدهای مختلف createGenerator و createParser به کلاس های مورد نظر دسترسی پیدا میکنیم.
تولید JSON در Streaming API
در این روش ابتدا شی ای از کلاس JsonGenerator را تولید میکنیم. دادهی تولید شده میتواند در یکی از موارد زیر نوشته شود. محل نوشته شدن داده به عنوان پارامتر اول در متد createGenerator وارد میشود:
- DataOutput
- File
- OutputStream
- Writer
در مثال زیر یک شی از کلاس Employee (که در مقالهی قبل معرفی شد) به JSON تبدیل شده و در یک فایل ذخیره میشود.
private static void emp2json_StreamMethod(Employee emp) throws IOException { JsonFactory jsonFactory = new JsonFactory(); JsonGenerator generator = jsonFactory.createGenerator(new File("jsonWithStreamAPI.json"), JsonEncoding.UTF8); //Start of object for emp generator.writeStartObject(); //name generator.writeNumberField("id", emp.getId()); generator.writeStringField("firstName", emp.getFirstName()); generator.writeStringField("lastName", emp.getLastName()); //phoneNumbersList generator.writeFieldName("phoneNumbers"); generator.writeStartArray(); for (String phoneNumber : emp.getPhoneNumbers()) { generator.writeString(phoneNumber); } generator.writeEndArray(); //Address Object generator.writeFieldName("address"); generator.writeStartObject(); generator.writeStringField("city", emp.getAddress().getCity()); generator.writeStringField("street", emp.getAddress().getStreet()); generator.writeNumberField("zipCode", emp.getAddress().getZipCode()); generator.writeEndObject(); //end of obj for emp generator.writeEndObject(); generator.close(); System.out.println("JSON storage with [Stream Method] is done!"); }
متدهای استفادهشده و وظیفهی هر کدام به صورت خلاصه به شرح زیر است:
توضیح | نام متد |
کاراکتر «}» را مینویسد | writeStartObject() |
یک فیلد عددی مینویسد، fieldName و value را با «:» از هم جدا میکند | writeNumberField(“String”,number) |
یک فیلد رشتهای مینویسد، fieldName و value را با «:» از هم جدا میکند | writeStringField(“String”,”String”) |
نام یک فیلد را نوشته و بعد از آن «:» قرار میدهد | writeFieldName(“String”) |
کاراکتر «]» را مینویسد | writeStartArray() |
یک رشته مینویسد. در صورتی که نیاز به جدا کردن المانهای یک آرایه از رشتهها باشد، از کاراکتر «,» به این منظور استفاده میکند | writeString(“String”) |
کاراکتر «[» را مینویسد | writeEndArray() |
کاراکتر «{» را مینویسد | writeEndObject() |
خواندن JSON در Streaming API
کلاس JsonFactory متدهای متنوع createParser دارد که هر کدام میتوانند منبع متفاوتی از دادهی JSON ای باشند. این منبع میتواند از میان گزینههای زیر انتخاب شود:
- Reader
- InputStream
- URL
- byte array
- char array
روش کار JsonParser به این صورت است که ابتدا دادهی JSON ای را به token های مختلف میشکند و لیستی از token ها تولید میکند. هر شیء JSON به یک token تبدیل میشود. به عنوان مثال کاراکتر شروع کلاس «}» تبدیل به یک token میشود. هر فیلد JSON از key/value تشکیل شده است. مقدار value میتواند مقادیر سادهای مانند یک رشته یا یک مقدار عددی باشد، یا مقادیر غیرسادهای مانند آرایه یا یک شی.
برای مقادیر ساده، مقدار key و value هر کدام در یک token ذخیره میشوند. اما برای مقادیر غیر ساده، تکتک کاراکترهای «{»، «}»، «[» یا «]» و مقادیر سادهی داخل شی یا آرایه در token مجزا قرار داده میشود. با پیمایش این لیست و ذخیرهی مقادیر در فیلدهای مناسب داده میتوان POJO را از روی JSON تولید کرد. مثال زیر یک employee را نشان میدهد. همان طور که قبلا اشاره شد، کد های نوشته شده با Streaming API عموما طولانی هستند. جهت رعایت اختصار از آوردن قسمتهایی از کد صرف نظر میکنیم.
private static Employee json2emp_StreamMethod() throws JsonParseException, IOException{ JsonFactory jsonFactory = new JsonFactory(); JsonParser parser = jsonFactory.createParser(new File("jsonWithStreamAPI.json")); Employee emp = new Employee(); token = parser.nextToken(); if (!token.equals(JsonToken.START_OBJECT)) { throw new IOException("Expected data to start with an Object"); } token = parser.nextToken(); while (true) { if (token == null){ break; } if(token.equals(JsonToken.END_OBJECT)){ break; } System.out.println("token is: "+token); String fieldName = parser.getCurrentName(); System.out.println("field name is "+fieldName); token = parser.nextToken(); if (fieldName.equals("id")) { emp.setId(parser.getIntValue()); }else if (fieldName.equals("firstName")) { emp.setFirstName(parser.getText()); }else if (fieldName.equals("lastName")) { emp.setLastName(parser.getText()); }else if (fieldName.equals("phoneNumbers")) { readPhoneNumberArray(parser, emp); }else if (fieldName.equals("address")) { readAddrssObject(parser, emp); } token = parser.nextToken(); } parser.close(); return emp; }
در تکه کد فوق شروع به پیمایش token ها میکنیم. نوع هر token با مقایسهی آن با انواع استانداردی که در JsonToken enumeration وجود دارد تعیین میشود. در صورتی که token از نوع JsonToken.FIELD_NAME باشد، میتوان گفت token بعدی یک «مقدار» است. مقادیر ساده را میتوان با استفاده از متدهایی مانند getIntValue و getText حاصل کرد. مقادیر مرکب که یک شی یا آرایه هستند را میتوان دوباره به token ها تجزیه کرده و مورد استفاده قرار داد.
ویژگی Streaming API
این روش بسیار قدرتمند است اما کار با آن نیازمند کدنویسی زیادی است. همانطور که قبلا اشاره شد دو متد Tree Model و Data Binding، پشت صحنه از این روش برای تعامل با JSON استفاده میکنند. طراحان بستهینرمافزاری میتوانستند این روش را از دید مخفی کنند. هدف از در معرض استفاده قرار دادن کلاس های Streaming Method این است که به برنامهنویس امکان دهد در مواردی که نیازمند بازده بالاتری است، از آن استفاده کند. کنترل کامل بر مراحل تولید و خواندن متن JSON ای از نقاط قوت این روش به شمار میرود.
.
.
.
آدرس کانال تلگرام: JavaCupIR@
آدرس اکانت توییتر: JavaCupIR@
آدرس صفحه اینستاگرام: javacup.ir
آدرس گروه لینکدین: Iranian Java Developers