Java 带改装2的多个变流器

Java 带改装2的多个变流器,java,generics,gson,retrofit,hateoas,Java,Generics,Gson,Retrofit,Hateoas,我有一个REST服务,并设法用下面的代码与它对话(用作转换引擎),但当我尝试(stallone和stallone2)时,应用程序将始终拾取第一个转换器,而不是适合响应类型的转换器,这当然会导致错误 我如何避免重复的改装,而这些改装只在小的类型细节上有所不同? 公共接口史泰龙{ @获取(“/discovery”) 调用discover(); @POST() 调用登录名(@Url字符串Url,@Body LoginRequest secret); } publicstaticvoidmain(St

我有一个REST服务,并设法用下面的代码与它对话(用作转换引擎),但当我尝试(
stallone
stallone2
)时,应用程序将始终拾取第一个转换器,而不是适合响应类型的转换器,这当然会导致错误

我如何避免重复的改装,而这些改装只在小的类型细节上有所不同?

公共接口史泰龙{
@获取(“/discovery”)
调用discover();
@POST()
调用登录名(@Url字符串Url,@Body LoginRequest secret);
}
publicstaticvoidmain(String…args)抛出IOException{
//为每个支持的(返回)类型初始化转换器
final Stallone Stallone=新改装.Builder()
.baseUrl(基本)
.addConverterFactory(HALConverterFactory.create(DiscoveryResponse.class))
.build().create(Stallone.class);
最终史泰龙史泰龙2=新改装.Builder()
.baseUrl(基本)
.addConverterFactory(HALConverterFactory.create(LoginResponse.class))
.build().create(Stallone.class);
//遵循HAL链接
Response-Response=stallone.discover().execute();
System.out.println(response.code()+“”+response.message());
Assert.assertNotNull(response.body());
字符串loginPath=response.body().getLogin();
Assert.assertEquals(loginPath,“/login”);
//点击另一个链接
if(loginPath.startsWith(“/”)
loginPath=loginPath.substring(1);
响应响应2=
stallone2.登录(登录路径,
新登录请求(AUTH0TOKEN,null)).execute();
System.out.println(response2.code()+“”+response2.message());
Assert.assertNotNull(response2.body());
字符串setupPath=response2.body().getSetup();
Assert.assertEquals(setupPath,“/setup”);
System.out.println(“一切正常!”);
}
公共最终类HALConverterFactory扩展了Converter.Factory{
私人最终Gson Gson;
公共静态HALConverterFactory创建(类类型){
返回新的HALConverterFactory(类型);
}
私有HALConverterFactory(类类型){
如果(!HalResource.class.isAssignableFrom(类型))
抛出新的NullPointerException(“类型应该是HalResource的子类”);
GsonBuilder=新的GsonBuilder();
registerTypeAdapter(HalResource.class,新的HalSerializer());
registerTypeAdapter(HalResource.class,新的HalDeserializer(类型));
setExclusionStrategies(新的HalExclusionStrategy());
this.gson=builder.create();
}
@凌驾
公共转换器fromResponseBy(类型,注释[]注释){
返回新的HALResponseBodyConverter(gson);
}

@覆盖公共转换器如果类型不匹配,则需要从转换器工厂返回
null
。将
类保留在一个字段中,以便与之进行比较

@Override
public Converter<ResponseBody, ?> fromResponseBody(Type type, Annotation[] annotations) {
  if (!this.type.equals(type)) {
    return null;
  }
  return new HALResponseBodyConverter<>(gson);
}
您可以查看repo中的Wire converter,它提供了完整的示例。

包ch.halarious.core;
package ch.halarious.core;

import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Custom Hal Deserializer  
 *
 * @author jaren
 */
public class CustomHalDeserializer extends HalDeserializer {

    /**
     * Intialisiert ein HalDeserializer-Objekt
     *
     * @param targetType Typ, den wir eigentlich deserialisieren sollten
     */
    public CustomHalDeserializer(Class<?> targetType) {
        super(targetType);
    }

    class CustomArrayList extends ArrayList implements HalResource{}

    public HalResource deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context, Class<?> targetType) throws JsonParseException {
        // Es handelt sich um ein JSON-Objekt.
        JsonObject jsonObject = json.getAsJsonObject();
        JsonObject embeddedRoot = jsonObject.getAsJsonObject(HalConstants.EMBEDDED_ROOT);

        if(embeddedRoot != null){
            Set<Map.Entry<String, JsonElement>> set = embeddedRoot.entrySet();
            if(set.toArray().length == 1){
                JsonArray ja = embeddedRoot.getAsJsonArray(set.iterator().next().getKey());
                if(ja.isJsonArray()) {
                    CustomArrayList arrayResult = new CustomArrayList();
                    Iterator<JsonElement> i = ja.iterator();
                    while(i.hasNext()){
                        JsonElement je = i.next();
                        arrayResult.add(super.deserialize(je, typeOfT, context, targetType));
                    }
                    return arrayResult;
                }
            }
        }

        return super.deserialize(json, typeOfT, context, targetType);
    }
}
导入com.google.gson.JsonArray; 导入com.google.gson.JsonDeserializationContext; 导入com.google.gson.JsonElement; 导入com.google.gson.JsonObject; 导入com.google.gson.JsonParseException; 导入java.lang.reflect.Type; 导入java.util.ArrayList; 导入java.util.Iterator; 导入java.util.Map; 导入java.util.Set; /** *自定义Hal反序列化器 * *@作者jaren */ 公共类CustomHalDeserializer扩展HalDeserializer{ /** *反序列化器对象初始化器 * *@param targetType Typ,den wir eigntlich反序列化 */ 公共CustomHalDeserializer(类targetType){ 超级(目标型); } 类CustomArrayList扩展了ArrayList实现了HalResource{} 公共资源反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext,类targetType)引发JsonParseException{ //这是我的目标。 JsonObject JsonObject=json.getAsJsonObject(); JsonObject embeddedRoot=JsonObject.getAsJsonObject(HalConstants.EMBEDDED_ROOT); if(embeddedRoot!=null){ Set=embeddedRoot.entrySet(); if(set.toArray().length==1){ JsonArray ja=embeddedRoot.getAsJsonArray(set.iterator().next().getKey()); if(ja.isJsonArray()){ CustomArrayList arrayResult=新的CustomArrayList(); 迭代器i=ja.Iterator(); while(i.hasNext()){ JsonElement je=i.next(); add(super.deserialize(je,typeOfT,context,targetType)); } 返回arrayResult; } } } 返回super.deserialize(json、typeOfT、context、targetType); } }
我所做的与@jake wharton在中所说的几乎相同,但添加了一些更改:

public class GenericConverterFactory<T> extends Converter.Factory {

    private final Class<T> clazz;

    public static GenericConverterFactory create(Class<T> clazz) {
        return new GenericConverterFactory(clazz);
    }

    private GenericConverterFactory(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        if (!isNeededType(type)) {
            return null;
        }

        // some converter that knows how to return your specific type T
        return new GenericConverter(clazz);
    }

    private boolean isNeededType(Type type) {
        if(type instanceof GenericArrayType) {
            // if type is array we should check if it has the same component as our factory clazz
            // if our factory clazz is not array getComponentType will return null
            return ((GenericArrayType) type).getGenericComponentType().equals(clazz.getComponentType());
        } else if(clazz.getComponentType() == null) {
            // if factory clazz is not array and type is not array too
            // type is just a Class<?> and we should check if they are equal
            return clazz.equals(type);
        } else {
            // otherwise our clazz is array and type is not
            return false;
        }
    }
}
对于方法
getCustomElements()
类型将是
GenericArrayType
GenericComponentType
作为
CustomElement.class
,对于第二个方法类型将只是
CustomElement.class


不确定这是否是最好的解决方案,但对我来说它能起作用。希望它能有所帮助。

在我的情况下,我只需要将一个类序列化和反序列化为XML。对于其他所有我需要的Json。因此,我注册了如下适配器:

retrofit = new Retrofit.Builder()
                .baseUrl(BuildConfig.BASE_URL)
                .addConverterFactory(EditUserXmlConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(createGson()))
                .client(httpClient.build())
                .build();
由于无法扩展
SimpleXmlConverterFactory
(很遗憾),我不得不使用自己的类并更改以下行:

if (!(type instanceof Class)) return null;


通过这种方式,只有类型为
NeedToBeXML
的响应和请求才会转换为XML以及其他JSON。

什么是
GsonRequestBodyConverter
?在哪里可以找到EditUserXmlConverterFactory?还有,在哪里编写:if(type!=NeedToBeXML.class)返回null?
retrofit = new Retrofit.Builder()
                .baseUrl(BuildConfig.BASE_URL)
                .addConverterFactory(EditUserXmlConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(createGson()))
                .client(httpClient.build())
                .build();
if (!(type instanceof Class)) return null;
if (type != NeedToBeXML.class) return null;