簡體   English   中英

Java Android Gson從響應服務器將布爾值轉換為int

[英]Java Android Gson convert boolean to int from response server

伙計們,幫幫我! 請提出一個簡單的解決方案,將Android中的boolean類型從服務器轉換為int :)當我登錄時,我會像這樣從服務器得到響應:

{"status":{"error":0,"code":200,"message":"OK"},"response":{"profile":{"id":114,"username":"k@gmail.com","full_name":"k","phone":"9999999","verified":1,"admin":0,"allow_dev":false,"company":{"id":9,"name":"ООО \"Фингерз медиа\"","email":"info@fingers.by","sample":null,"logo":"http://storage.guardian-glass.fingersmedia.by/0cb56968b3cec1bba301db8d51d1015e.jpg"}},"access_token":"15629e234e04a54a5a44ef2aa4eccb1d"}}

然后我得到undefined exception: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected NUMBER but was BOOLEAN

發生這種情況是因為JsonElement“ allow_dev ”是來自服務器的布爾值 ,並且在Android中,我具有像int這樣的“ allow_dev ”。

這是登錄方法:

 private void login(String email, String pass) {
    showProgress();
    JsonObject params = new JsonObject();
    params.addProperty("username", email);
    params.addProperty("password", pass);
    UserOperationsTask task = new UserOperationsTask(UserOperationsTask.TaskMode.MODE_LOGIN, params) {
        @Override
        public void onLoadFinished(Bundle res) {
            hideProgress();
            String errorMessage = res.getString(UserOperationsTask.RESULT_ERROR_STRING);
            if (errorMessage != null) {
                showMessage(getString(R.string.login_error), getString(R.string.server_request_error));
            } else {
                String json = res.getString(UserOperationsTask.RESULT_JSON_STRING);
                if (json != null) {
                    JsonParser parser = new JsonParser();
                    JsonObject responseData = parser.parse(json).getAsJsonObject();
                    JsonObject companyObj = responseData.getAsJsonObject("profile").getAsJsonObject("company");
                   }
                setRegisteredMode();
            }
        }
    };
    task.execute(this);
}

此方法解析響應,我試圖將allow_dev類型從boolean轉換為int,但是我不明白我是否做得對?

private Bundle parseProfileResponse(Context context, JsonObject responseData) {
    Log.d(TAG, "parseProfileResponse");

    // I tried convert allow_dev type from boolean to int
    String allow_dev_server = String.valueOf(responseData.get("allow_dev"));
    boolean b = allow_dev_server.equals("true");
    int allow_dev = b ? 1 : 0; // true == 1
    Profile profile;
    profile = GsonHolder.getGSONInstance().fromJson(responseData.getAsJsonObject("profile"), Profile.class);
    profile.allow_dev = allow_dev;

    Bundle res = new Bundle();
    res.putParcelable(RESULT_OBJ, profile);
    res.putString(RESULT_JSON_STRING, responseData.toString());
    try {
        Cache.saveToCache(context, profile);
    } catch (RemoteException e) {
        Log.d(TAG, "parseAuthResponse RemoteException: " + e.toString());
        res.putString(RESULT_ERROR_STRING, context.getString(R.string.database_error));
    } catch (OperationApplicationException e) {
        Log.d(TAG, "parseAuthResponse OperationApplicationException: " + e.toString());
        res.putString(RESULT_ERROR_STRING, context.getString(R.string.database_error));
    }
    return res;
}

我必須獲取“ allow_dev ”,將其轉換為int並寫入數據庫。

如果您可以切換到映射,則可以使用靜態類型所提供的所有功能,與弱“類型化”的JsonElement及其子類進行比較。 它具有幾個優點:編譯時檢查,更健壯的代碼,IDE支持等。主要缺點是您必須編寫自定義映射,但是那里的工具(以及在線工具)可以嘗試根據以下內容生成簡單的映射類:給定的示例JSON(例如,此處的一種非常流行的工具: http : //www.jsonschema2pojo.org/ )。

現在,讓我們創建一些映射。 如下所示的映射很少使用: final字段(用於“服務器響應”,不應通過編程方式進行修改; Gson始終可以分配此類字段); 非基元為null ,某些基元類型的默認值會欺騙編譯器(例如Integer.value(0)而不是簡單的0 :否則, javac可能內聯常量,因此Gson不會影響它們); 沒有吸氣劑/吸氣劑(數據傳輸對象只是數據包,但是的,吸氣劑可以更好地工作)。 無論如何,您都可以使用自己的樣式,並且以下映射用於演示目的(映射代碼甚至具有緊湊的格式:每行一個屬性折疊注釋)。

final class Response<T> {
    final Status status = null;
    final T response = null;
}

final class Status {
    final int error = Integer.valueOf(0);
    final int code = Integer.valueOf(0);
    final String message = null;
}

final class ProfileAndAccessToken {
    final Profile profile = null;
    @SerializedName("access_token") final String accessToken = null;
}

final class Profile {
    final int id = Integer.valueOf(0);
    final String username = null;
    @SerializedName("full_name") final String fullName = null;
    final String phone = null;
    final int verified = Integer.valueOf(0);
    final int admin = Integer.valueOf(0);
    @SerializedName("allow_dev") @JsonAdapter(BooleanToIntTypeAdapter.class) final int allowDev = Integer.valueOf(0);
    final Company company = null;
}

final class Company {
    final int id = Integer.valueOf(0);
    final String name = null;
    final String email = null;
    final String sample = null;
    final URL logo = null;
}

請注意上面的兩個注釋:

  • @SerializedName -此注釋可以“重命名”字段,因此您甚至可以使用特殊字符(但是不建議使用,通常用於將傳入的JSON屬性名稱映射到javaCamelNamingConventions)。
  • @JsonAdapter -此批注可以將特殊類型的適配器“附加”到某個字段,以便可以將JSON屬性轉換為給定的字段,反之亦然。

現在,讓我們實現一個類型適配器,該適配器可以將傳入的boolean值轉換為本地int值,反之亦然。 請注意,類型適配器以流方式工作,因此您必須在讀取期間動態讀取JSON令牌流,​​並且當然必須在寫入期間生成JSON令牌流。

final class BooleanToIntTypeAdapter
        extends TypeAdapter<Integer> {

    // Public constructors may be evil, and let expose as less as possible
    // Gson can still instantiate this type adapter itself  
    private BooleanToIntTypeAdapter() {
    }

    @Override
    @SuppressWarnings("resource")
    public void write(final JsonWriter out, final Integer value)
            throws IOException {
        // If the given value is null, we must write the `null` token to the output JSON tokens stream anyway in order not to break JSON documents
        if ( value == null ) {
            out.nullValue();
            return;
        }
        // Let's assume that we can accept either 0 or 1 that are mapped to false and true respectively
        switch ( value ) {
        case 0:
            out.value(false);
            break;
        case 1:
            out.value(true);
            break;
        default:
            // Or throw an exception as fast as we can
            throw new IllegalArgumentException("Cannot convert " + value + " to a boolean literal");
        }
    }

    @Override
    public Integer read(final JsonReader in)
            throws IOException {
        // Peek the next token type, and if it's null, then return null value too
        if ( in.peek() == NULL ) {
            return null;
        }
        // Otherwise parse the next token as boolean and map it either to 1 or 0
        return in.nextBoolean() ? 1 : 0;
    }

}

這就是Gson您所需要的。 現在,對於整個JSON,由於響應映射類是通用的,因此您必須告訴Gson T是什么。 Gson在fromJson方法中接受java.lang.reflect.Type ,並且此類型可以同時包含原始和參數化類型,因此Gson可以更准確地進行(反)序列化。

private static final Type profileAndAccessTokenResponse = new TypeToken<Response<ProfileAndAccessToken>>() {
}.getType();

final Response<ProfileAndAccessToken> response = gson.fromJson(JSON, profileAndAccessTokenResponse);
System.out.println(response.response.profile.allowDev);
System.out.println(gson.toJson(response, profileAndAccessTokenResponse));

輸出:

0
{ “狀態”:{ “錯誤”:0 “代碼”:200, “消息”: “OK”}, “響應”:{ “輪廓”:{ “ID”:114, “用戶名”:“K @ gmail.com”, “FULL_NAME”: “K”, “手機”: “9999999”, “驗證”:1, “管理員”:0, “allow_dev”:假的, “公司”:{ “ID”:9, “名稱”:“ООО\\”Фингерзмедиа\\“”,“電子郵件”:“ info@fingers.by”,“徽標”:“ http://storage.guardian-glass.fingersmedia.by/0cb56968b3cec1bba301db8d51d1015e.jpg ” } “的access_token”: “15629e234e04a54a5a44ef2aa4eccb1d”}}

請注意,第一行是0 :這是使用BooleanToIntTypeAdapter生成的。 返回您的代碼:

String allow_dev_server = String.valueOf(responseData.get("allow_dev"));
boolean b = allow_dev_server.equals("true");
int allow_dev = b ? 1 : 0; // true == 1
Profile profile;
profile = GsonHolder.getGSONInstance().fromJson(responseData.getAsJsonObject("profile"), Profile.class);
profile.allow_dev = allow_dev;

可以替換為簡單的:

final Profile profile = GsonHolder.getGSONInstance().fromJson(responseData.getAsJsonObject("profile"), Profile.class)
// now `Profile.allowDev` is 0 or 1 automatically

請注意, responseData可以替換為特定的映射,因此您甚至無法在那一行進行解析:可能您可以將整個response對象簡單地傳遞為類映射,而不是parseProfileResponse中的JsonObject parseProfileResponse -這樣會更健壯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM