Mam HATEOAS (HAL) usługi REST i udało nam się porozmawiać z nim o poniższy kod (używając jak silnik konwersji), ale gdy próbuję merge the converters (stallone
i stallone2
), aplikacja będzie zawsze podnieść pierwszy konwerter, zamiast tego, który jest odpowiedni dla typu odpowiedzi, co oczywiście prowadzi do błędu.Wiele konwerterów z modernizacją 2
Jak mogę uniknąć duplikowania modyfikacji, które różnią się tylko szczegółem małego typu?
public interface Stallone {
@GET("/discovery")
Call<DiscoveryResponse> discover();
@POST()
Call<LoginResponse> login(@Url String url, @Body LoginRequest secret);
}
public static void main(String... args) throws IOException {
// Initialize a converter for each supported (return) type
final Stallone stallone = new Retrofit.Builder()
.baseUrl(BASE)
.addConverterFactory(HALConverterFactory.create(DiscoveryResponse.class))
.build().create(Stallone.class);
final Stallone stallone2 = new Retrofit.Builder()
.baseUrl(BASE)
.addConverterFactory(HALConverterFactory.create(LoginResponse.class))
.build().create(Stallone.class);
// Follow the HAL links
Response<DiscoveryResponse> response = stallone.discover().execute();
System.out.println(response.code() + " " + response.message());
Assert.assertNotNull(response.body());
String loginPath = response.body().getLogin();
Assert.assertEquals(loginPath, "/login");
// Follow another link
if (loginPath.startsWith("/"))
loginPath = loginPath.substring(1);
Response<LoginResponse> response2 =
stallone2.login(loginPath,
new LoginRequest(AUTH0TOKEN, null)).execute();
System.out.println(response2.code() + " " + response2.message());
Assert.assertNotNull(response2.body());
String setupPath = response2.body().getSetup();
Assert.assertEquals(setupPath, "/setup");
System.out.println("All OK!");
}
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, ?> fromResponseBody(Type type, Annotation[] annotations) {
return new HALResponseBodyConverter<>(gson);
}
@Override public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) {
return new GsonRequestBodyConverter<>(gson, type);
}
}
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) {
}
}
}
Ponownie, problem jest, że podczas próby skrócić powyższy tak:
final Stallone stallone = new Retrofit.Builder()
.baseUrl(BASE)
.addConverterFactory(HALConverterFactory.create(DiscoveryResponse.class))
.addConverterFactory(HALConverterFactory.create(LoginResponse.class))
.build().create(Stallone.class);
dostaniesz wyjątek u Linia Response<LoginResponse> response2 = ...
:
Wyjątek w wątku "main" java.lang.ClassCastException: com.example.retrofit.DiscoveryResponse nie mogą być oddane do com.example.retrofit.LoginResponse
Co to jest 'GsonRequestBodyConverter'? – naXa