簡単なRESTエンドポイントを作成しました:
http://<server_address>:3000/sizes
このURLは、次のようにjson arrayを含む非常に単純な応答を返します。
[
{ "id": 1, "name": "Small", "active": true },
{ "id": 2, "name": "Medium", "active": true },
{ "id": 3, "name": "Large", "active": true }
]
今、私はしようとしているGSONでRetrofit 2を使用してこの応答を消費する。
モデルを追加しました:
@lombok.AllArgsConstructor
@lombok.EqualsAndHashCode
@lombok.ToString
public class Size {
private int id;
private String name;
private boolean active;
@SerializedName("created_at")
private String createdAt;
@SerializedName("updated_at")
private String updatedAt;
}
そしてサービス:
public interface Service {
@GET("sizes")
Call<List<Size>> loadSizes();
}
レトロフィットをインスタンス化しました:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://<server_address>:3000")
.addConverterFactory(GsonConverterFactory.create())
.build();
そして私のサービス:
Service service = retrofit.create(Service.class);
次に、データを呼び出そうとします。
service.loadSizes().enqueue(new Callback<List<Size>>() {
@Override
public void onResponse(Call<List<Size>> call, Response<List<Size>> response) {
for(Size size: response.body()) {
System.out.println(size.toString());
}
}
@Override
public void onFailure(Call<List<Size>> call, Throwable t) {
System.out.println(t.getMessage());
}
});
例外で終わるもの:
Java.lang.IllegalStateException:BEGIN_OBJECTが予期されていたが、STRINGでした行1列18のパス$ [0] .name
エラーの原因はREST APIが配列でもオブジェクトでもない応答を返すであると思います。
RESTサービスは変更できませんなので、応答はそのままである必要があります。
また、純粋なGSONを使用した上記のjsonの逆シリアル化は、次の方法で実行できます。
Type sizesType = new TypeToken<List<Size>>(){}.getType();
List<Size> size = new Gson().fromJson(json, sizesType);
しかし、これを使用するためにRetrofit 2を作成する方法はわかりません。
前もって感謝します。
おもしろい事実は...私のコードはまったく問題ありません。少なくとも上記の質問で提示されたもの。
Size
モデルから1行削除しました。
コード自体(特にRetrofitの構成)に焦点を当てたため、インポートを完全に無視しました。
それは判明しました-モデルのフィールドにSize
クラスを入力し始めたときにString
モデルを実装しているとき:
name
createdAt
updatedAt
IntelliJ IDEAのコード補完が私に提案した
Java.lang.String
ではありませんcom.Sun.org.Apache.xpath.internal.operations.String
Gson
の逆シリアル化を完全に台無しにしたもの。
報酬に関しては...
私は自分自身の答えを有効としてマークすることにしました。どうして?
素晴らしいサービスに感謝します。
賞金は1つしかないので、報酬を決定しました xiaoyaoworm 彼のコードは私のニーズに合っているので(質問には書いていませんが、このようなシンプルなサービスを書くというアイデアは-提示したとおりです)私の質問では-エンドユーザーの実装の詳細から非表示にし、JsonArray
などを使用しないでください [〜#〜] bnk [〜#〜] response)。
xiaoyaoworm の答えの唯一の問題は、Size
モデルは注釈を必要としないことを示唆したことです引用されたJSONの例の完全な誤り。
上記の場合、Size
モデルの正確な2つのフィールドには注釈が必要です-created_at
およびupdated_at
。
converter-gson
ライブラリのいくつかのバージョンもテストしました( xiaoyaoworm は私以外のものを使用しています)-何も変更していません。注釈が必要でした。
それ以外の場合-再び、多くの感謝!
最近、レトロフィット2に関連する1つのプロジェクトを終えました。私のソースに基づいて、私はあなたのすべてのものを私のプロジェクトにコピーして試してみて、いくつかの小さな変更を加えます。それは私の側でうまくいきます。
Build.gradleで、これらを追加します。
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.okhttp3:okhttp:3.1.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
モデル:(UPDATE:tommusの場合、createdAtおよびupdatedAtが彼のjson応答サンプルに表示されるようになりました。モデル内の名前がjson responeと異なるため、これら2つの値には注釈が必要です))
public class Size {
private int id;
private String name;
private boolean active;
@SerializedName("created_at")
private String createdAt;
@SerializedName("updated_at")
private String updatedAt;
}
サービス:(お持ちのものとまったく同じ)
public interface service {
@GET("sizes")
Call<List<Size>> loadSizes();
}
RestClient:(ここにログを追加し、すべてのリクエスト情報とレスポンス情報を表示できるように、Localhostではなくサーバーを使用するように注意してくださいURLのIPアドレス)
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.xiaoyaoworm.prolificlibrary.test.Service;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RestClient {
private static Service service;
public static Service getClient() {
if (service == null) {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
// Add logging into retrofit 2.0
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.interceptors().add(logging);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://YOURSERVERIPNOTLOCALHOST:3000/")
.addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient.build()).build();
service = retrofit.create(Service.class);
}
return service;
}
}
アクティビティで、次の関数を追加してコードを実行します:(これまでとまったく同じです。応答はサイズのリストになります)
private void loadSize() {
Service serviceAPI = RestClient.getClient();
Call<List<Size>> loadSizeCall = serviceAPI.loadSizes();
loadSizeCall.enqueue(new Callback<List<Size>>() {
@Override
public void onResponse(Call<List<Size>> call, Response<List<Size>> response) {
for(Size size: response.body()) {
System.out.println(size.toString());
}
}
@Override
public void onFailure(Call<List<Size>> call, Throwable t) {
System.out.println(t.getMessage());
}
});
}
Git POST PUT DELETEが機能する。retrofit2.0を使用して、これを参照として使用できます。 My Github retrofit2.0 repo
以下を使用してください:
build.gradleファイル:
dependencies {
...
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.google.code.gson:gson:2.6.2'
}
WebAPIService.Java:
public interface WebAPIService {
@GET("/json.txt") // I use a simple json file to get the JSON Array as yours
Call<JsonArray> readJsonArray();
}
Size.Java:
public class Size {
@SerializedName("id")
private int id;
@SerializedName("name")
private String name;
@SerializedName("active")
private boolean active;
@SerializedName("created_At")
private String createdAt;
@SerializedName("updated_at")
private String updatedAt;
}
MainActivity.Java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://...")
.addConverterFactory(GsonConverterFactory.create())
.build();
WebAPIService service = retrofit.create(WebAPIService.class);
Call<JsonArray> jsonCall = service.readJsonArray();
jsonCall.enqueue(new Callback<JsonArray>() {
@Override
public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
String jsonString = response.body().toString();
Log.i("onResponse", jsonString);
Type listType = new TypeToken<List<Size>>() {}.getType();
List<Size> yourList = new Gson().fromJson(jsonString, listType);
Log.i("onResponse", yourList.toString());
}
@Override
public void onFailure(Call<JsonArray> call, Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
デバッグのスクリーンショットは次のとおりです。
更新:次のオプションも使用できます。
@GET("/json.txt")
Call<List<Size>> readList();
そして
Call<List<Size>> listCall1 = service.readList();
listCall1.enqueue(new Callback<List<Size>>() {
@Override
public void onResponse(Call<List<Size>> call, Response<List<Size>> response) {
for (Size size : response.body()){
Log.i("onResponse", size.toString());
}
}
@Override
public void onFailure(Call<List<Size>> call, Throwable t) {
Log.e("onFailure", t.toString());
}
});