【问题标题】:Retrofit with Halarious and Teleport.org使用 Halarious 和 Teleport.org 进行改造
【发布时间】:2016-07-23 20:17:00
【问题描述】:

我正在开发一个使用 teleport.org API 列出城市区域的小型 android 应用。为此,我使用了以下响应 URL:

https://api.teleport.org/api/urban_areas/

响应如下所示:

{
  "_links": {
    "curies": [
      {
        "href": "https://developers.teleport.org/api/resources/Location/#!/relations/{rel}/",
        "name": "location",
        "templated": true
      }
    ],
    "self": {
      "href": "https://api.teleport.org/api/urban_areas/"
    },
    "ua:item": [
      {
        "href": "https://api.teleport.org/api/urban_areas/teleport:u173z/",
        "name": "Amsterdam"
      }
    ]
  },
  "count": 153
}

这给了我一个 HAL 格式的 json 文件。由于我使用改造来加载我的 API,我需要一个自定义转换器来获取存储在 POJO 类中的信息。我为此选择了Halarious。 http://halarious.ch/

我是这样设置的。

主活动:

String url = "https://api.teleport.org/api/";
TextView txt_city;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    txt_city = (TextView) findViewById(R.id.txt_city);

    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

    getCities();

}

void getCities() {
    //Creating Rest Services
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(HALConverterFactory.create(CityData.class))
            .build();

    RestInterface service = retrofit.create(RestInterface.class);

    Call<CityData> call = service.getCityList();


    call.enqueue(new Callback<CityData>() {
        @Override
        public void onResponse(Call<CityData> call, Response<CityData> response) {
            try {
                String city = response.body().getUaItem().get(0).getName();
                //Log.e("stad", city);

                txt_city.setText("city 12  :  " + city);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<CityData> call, Throwable t) {
            // Log error here since request failed
        }
    });
}

HALConverterFactory.class:

public final class HALConverterFactory extends Converter.Factory {
    private final Gson gson;

    public static HALConverterFactory create(Class<?> type) {
        return new HALConverterFactory(type);
    }

    private HALConverterFactory(Class<?> type) {
        if (!HalResource.class.isAssignableFrom(type))
            throw new NullPointerException("Type should be a subclass of HalResource");
        GsonBuilder builder = new GsonBuilder();
        builder.registerTypeAdapter(HalResource.class, new HalSerializer());
        builder.registerTypeAdapter(HalResource.class, new HalDeserializer(type));
        builder.setExclusionStrategies(new HalExclusionStrategy());
        this.gson = builder.create();
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new HALResponseBodyConverter<>(gson);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        return super.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
    }
}

HALResponseBodyConverter.class:

final class HALResponseBodyConverter<T extends HalResource> implements Converter<ResponseBody, T>{

    private final Gson gson;

    HALResponseBodyConverter(Gson gson) {
        this.gson = gson;
    }

    @Override public T convert(ResponseBody value) throws IOException {
        BufferedSource source = value.source();
        try {
            String s = source.readString(Charset.forName("UTF-8"));
            return (T) gson.fromJson(s, HalResource.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            closeQuietly(source);
        }
    }

    private static void closeQuietly(Closeable closeable) {
        if (closeable == null) return;
        try {
            closeable.close();
        } catch (IOException ignored) {
        }
    }
}

我有以下 POJO 课程。

城市数据:

public class CityData implements HalResource {

    @HalLink
    private List<Cury> curies = new ArrayList<Cury>();
    private Self self;
    private List<UaItem> uaItem = new ArrayList<UaItem>();
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();

    private Integer count;

    //getters and setters
}

UaItem:

public class UaItem implements HalResource {
    @HalLink
    private String href;
    private String name;
    private Map<String, Object> additionalProperties = new HashMap<String, Object>();
    //getters and setters
}

我现在想做的是检索以下内容:

String city = response.body().getUaItem().get(0).getName();

但问题是我的 getUaItem 完全是空的。它只是返回 []。所以 get(0) 是无用的,因为数组是空的。我可以得到计数,因为这是最高级别的,但是 UaItem 给我带来了问题。这是为什么呢?

亲切的问候,

沃特

【问题讨论】:

    标签: java android json api


    【解决方案1】:

    您需要在每个链接上添加@HalLink。你忘了把它添加到CityData.self

    如果您必须指定其他名称,只需使用name 属性即可。

    @HalLink(name = "ua:item")
    private List<UaItem> uaItem = new ArrayList<UaItem>();
    

    【讨论】:

      【解决方案2】:

      我认为这是因为原始响应变量名称是ua:Item,而不是uaItem。可能自动映射在这里不起作用。您可以通过显式写出变量名称来修复它:

      @serializedName("ua:item") private List<UaItem> uaItem = new ArrayList<UaItem>();
      

      【讨论】:

      • 我不在这个项目上,所以我无法检查这个。我们最终使用了没有 HAL 表示法的不同 API。所以把这个留在这里,让和我遇到同样问题的人尝试一下。现在会批准它,直到有人另有说明。
      • 它不起作用。您需要使用@HalLink(name = "ua:item")。看下面。
      猜你喜欢
      • 2018-05-03
      • 2014-07-28
      • 2018-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-24
      • 2016-12-31
      • 1970-01-01
      相关资源
      最近更新 更多