Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在带有泛型参数的泛型方法中使用Spring RestTemplate_Java_Spring_Generics_Jackson_Resttemplate - Fatal编程技术网

Java 在带有泛型参数的泛型方法中使用Spring RestTemplate

Java 在带有泛型参数的泛型方法中使用Spring RestTemplate,java,spring,generics,jackson,resttemplate,Java,Spring,Generics,Jackson,Resttemplate,要在SpringRESTTemplate中使用泛型类型,我们需要使用ParameterizedTypeReference() 假设我有课 public class MyClass { int users[]; public int[] getUsers() { return users; } public void setUsers(int[] users) {this.users = users;} } 还有一些包装类 public class ResponseWr

要在SpringRESTTemplate中使用泛型类型,我们需要使用
ParameterizedTypeReference
()

假设我有课

public class MyClass {
    int users[];

    public int[] getUsers() { return users; }
    public void setUsers(int[] users) {this.users = users;}
}
还有一些包装类

public class ResponseWrapper <T> {
    T response;

    public T getResponse () { return response; }
    public void setResponse(T response) {this.response = response;}
}
。。。我得到的不是
ResponseEntity
对象,而是
ResponseEntity
对象

我怎样才能解决这个问题?这是一个RestTemplate错误吗

更新1
感谢@Sotirios,我理解了这个概念。不幸的是,我是新注册的,所以我不能评论他的答案,所以就写在这里。我不确定我是否清楚如何使用
Map
Class
键(由@Sotirios在其答案末尾提出)实施拟议的方法来解决我的问题。有人能举个例子吗?

不,这不是一个bug。这是
参数化typereference
hack如何工作的结果

如果您看一下它的实现,它使用了哪些状态

返回表示实体的直接超类的类型 (类、接口、基元类型或void)由该类表示

如果超类是参数化类型,返回
类型
对象 必须准确反映源中使用的实际类型参数 代码。

所以,如果你使用

new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {}
new ParameterizedTypeReference<ResponseWrapper<T>>() {}
它将准确地为
ResponseWrapper
返回
类型
,因为这就是它在源代码中的显示方式

当Spring看到
T
,它实际上是一个
TypeVariable
对象时,它不知道要使用的类型,所以它使用它的默认值

您不能使用您建议的方式使用
ParameterizedTypeReference
,使其在接受任何类型的意义上具有通用性。考虑编写一个代码< >代码>代码>键<代码>类<代码>映射到预定义的<代码>参数化的TyPeRe><代码>该类。


您可以子类化
ParameterizedTypeReference
并重写其
getType
方法,以返回正确创建的
ParameterizedType

不,这不是错误。这是
参数化typereference
hack如何工作的结果

如果您看一下它的实现,它使用了哪些状态

返回表示实体的直接超类的类型 (类、接口、基元类型或void)由该类表示

如果超类是参数化类型,返回
类型
对象 必须准确反映源中使用的实际类型参数 代码。

所以,如果你使用

new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {}
new ParameterizedTypeReference<ResponseWrapper<T>>() {}
它将准确地为
ResponseWrapper
返回
类型
,因为这就是它在源代码中的显示方式

当Spring看到
T
,它实际上是一个
TypeVariable
对象时,它不知道要使用的类型,所以它使用它的默认值

您不能使用您建议的方式使用
ParameterizedTypeReference
,使其在接受任何类型的意义上具有通用性。考虑编写一个代码< >代码>代码>键<代码>类<代码>映射到预定义的<代码>参数化的TyPeRe><代码>该类。


您可以子类化
ParameterizedTypeReference
并重写其
getType
方法以返回正确创建的
ParameterizedType

正如Sotirios所解释的,您不能使用
ParameterizedTypeReference
,但是ParameterizedTypeReference仅用于向对象映射器提供
类型
,并且由于您拥有在类型擦除时被删除的类,因此您可以创建自己的类并将其传递给
RestTemplate
,以便对象映射器可以重建您需要的对象

首先,您需要实现ParameterizedType接口,您可以在GoogleGSON项目中找到一个实现。 将实现添加到项目中后,可以像下面这样扩展抽象
参数化TypeReference

class FakeParameteredTypeReference扩展了ParameteredTypeReference{
@凌驾
公共类型getType(){
类型[]responseWrapperActualTypes={MyClass.class};
ParameteredType responseWrapperType=新的ParameteredTypeImpl(
ResponseWrapper.class,
响应包装器实际类型,
无效的
);
返回响应包装器类型;
}
}
然后您可以将其传递给exchange功能:

template.exchange(
    uri,
    HttpMethod.POST,
    null,
    new FakeParameterizedTypeReference<ResponseWrapper<T>>());
template.exchange(
乌里,
HttpMethod.POST,
无效的
新的FakeParameteredTypeReference());

由于存在所有类型信息,对象映射器将正确构造
响应包装器
对象

,正如Sotirios所解释的,您不能使用
参数化类型引用
,但参数化类型引用仅用于向对象映射器提供
类型
,当类型擦除发生时,类会被删除,因此可以创建自己的类并将其传递给
restemplate
,以便对象映射器可以重建所需的对象

首先,您需要实现ParameterizedType接口,您可以在GoogleGSON项目中找到一个实现。 将实现添加到项目中后,可以像下面这样扩展抽象
参数化TypeReference

class FakeParameteredTypeReference扩展了ParameteredTypeReference{
@凌驾
公共类型getType(){
类型[]responseWrapperActualTypes={MyClass.class};
ParameteredType responseWrapperType=新的ParameteredTypeImpl(
ResponseWrapper.class,
响应包装器实际类型,
无效的
);
返回响应包装器类型;
}
}
然后您可以将其传递给exchange功能:

template.exchange(
    uri,
    HttpMethod.POST,
    null,
    new FakeParameterizedTypeReference<ResponseWrapper<T>>());
template.exchange(
乌里,
HttpMethod.POST,
无效的
新的FakeParameteredTypeReference());
在所有类型信息存在的情况下,对象映射器将正确地构造
template.exchange(
    uri,
    HttpMethod.POST,
    null,
    new FakeParameterizedTypeReference<ResponseWrapper<T>>());
    List<HttpMessageConverter<?>> oldConverters = new ArrayList<HttpMessageConverter<?>>();
    oldConverters.addAll(template.getMessageConverters());

    List<HttpMessageConverter<?>> stringConverter = new ArrayList<HttpMessageConverter<?>>();
    stringConverter.add(new StringHttpMessageConverter());

    template.setMessageConverters(stringConverter);
    ResponseEntity<String> response = template.exchange(uri, HttpMethod.GET, null, String.class);
     String body = null;
     List<T> result = new ArrayList<T>();
     ObjectMapper mapper = new ObjectMapper();

     if (response.hasBody()) {
        body = items.getBody();
        try {
            result = mapper.readValue(body, mapper.getTypeFactory().constructCollectionType(List.class, clazz));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            template.setMessageConverters(oldConverters);
        }
        ...
Map<Class<?>, ParameterizedTypeReference> typeReferences = new HashMap<>();
typeReferences.put(MyClass1.class, new ParameterizedTypeReference<ResponseWrapper<MyClass1>>() { });
typeReferences.put(MyClass2.class, new ParameterizedTypeReference<ResponseWrapper<MyClass2>>() { });

...

ParameterizedTypeReference typeRef = typeReferences.get(clazz);

ResponseEntity<ResponseWrapper<T>> response = restTemplate.exchange(
        uri, 
        HttpMethod.GET, 
        null, 
        typeRef);
public <T> ResponseWrapper<T> makeRequest(URI uri, final Class<T> clazz) {
   ResponseEntity<ResponseWrapper<T>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        new ParameterizedTypeReference<ResponseWrapper<T>>() {
            public Type getType() {
                return new MyParameterizedTypeImpl((ParameterizedType) super.getType(), new Type[] {clazz});
        }
    });
    return response;
}

public class MyParameterizedTypeImpl implements ParameterizedType {
    private ParameterizedType delegate;
    private Type[] actualTypeArguments;

    MyParameterizedTypeImpl(ParameterizedType delegate, Type[] actualTypeArguments) {
        this.delegate = delegate;
        this.actualTypeArguments = actualTypeArguments;
    }

    @Override
    public Type[] getActualTypeArguments() {
        return actualTypeArguments;
    }

    @Override
    public Type getRawType() {
        return delegate.getRawType();
    }

    @Override
    public Type getOwnerType() {
        return delegate.getOwnerType();
    }

}
static <K, V> TypeToken<Map<K, V>> mapToken(TypeToken<K> keyToken, TypeToken<V> valueToken) {
  return new TypeToken<Map<K, V>>() {}
    .where(new TypeParameter<K>() {}, keyToken)
    .where(new TypeParameter<V>() {}, valueToken);
}
import com.google.common.reflect.TypeToken;
import org.springframework.core.ParameterizedTypeReference;

import java.lang.reflect.Type;

public class ParameterizedTypeReferenceBuilder {

    public static <T> ParameterizedTypeReference<T> fromTypeToken(TypeToken<T> typeToken) {
        return new TypeTokenParameterizedTypeReference<>(typeToken);
    }

    private static class TypeTokenParameterizedTypeReference<T> extends ParameterizedTypeReference<T> {

        private final Type type;

        private TypeTokenParameterizedTypeReference(TypeToken<T> typeToken) {
            this.type = typeToken.getType();
        }

        @Override
        public Type getType() {
            return type;
        }

        @Override
        public boolean equals(Object obj) {
            return (this == obj || (obj instanceof ParameterizedTypeReference &&
                    this.type.equals(((ParameterizedTypeReference<?>) obj).getType())));
        }

        @Override
        public int hashCode() {
            return this.type.hashCode();
        }

        @Override
        public String toString() {
            return "ParameterizedTypeReference<" + this.type + ">";
        }

    }

}
public <T> ResponseWrapper<T> makeRequest(URI uri, Class<T> clazz) {
   ParameterizedTypeReference<ResponseWrapper<T>> responseTypeRef =
           ParameterizedTypeReferenceBuilder.fromTypeToken(
               new TypeToken<ResponseWrapper<T>>() {}
                   .where(new TypeParameter<T>() {}, clazz));
   ResponseEntity<ResponseWrapper<T>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        responseTypeRef);
    return response;
}
ResponseWrapper<MyClass> result = makeRequest(uri, MyClass.class);
public <T> ResponseWrapper<T> makeRequest(URI uri, TypeToken<T> resultTypeToken) {
   ParameterizedTypeReference<ResponseWrapper<T>> responseTypeRef =
           ParameterizedTypeReferenceBuilder.fromTypeToken(
               new TypeToken<ResponseWrapper<T>>() {}
                   .where(new TypeParameter<T>() {}, resultTypeToken));
   ResponseEntity<ResponseWrapper<T>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        responseTypeRef);
    return response;
}
ResponseWrapper<List<MyClass>> result = makeRequest(uri, new TypeToken<List<MyClass>>() {});
    ResolvableType resolvableType = ResolvableType.forClassWithGenerics(ListResultEntity.class, itemClass);
    ParameterizedTypeReference<ListResultEntity<T>> typeRef = ParameterizedTypeReference.forType(resolvableType.getType());
public <T> ResponseWrapper<T> makeRequest(URI uri, Class<T> clazz) {
   ResponseEntity<ResponseWrapper<T>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        ParameterizedTypeReference.forType(ResolvableType.forClassWithGenerics(ResponseWrapper.class, clazz)));
    return response;
}
private <REQ, RES> RES queryRemoteService(String url, HttpMethod method, REQ req, Class reqClass) {
    RES result = null;
    try {
        long startMillis = System.currentTimeMillis();

        // Set the Content-Type header
        HttpHeaders requestHeaders = new HttpHeaders();
        requestHeaders.setContentType(new MediaType("application","json"));            

        // Set the request entity
        HttpEntity<REQ> requestEntity = new HttpEntity<>(req, requestHeaders);

        // Create a new RestTemplate instance
        RestTemplate restTemplate = new RestTemplate();

        // Add the Jackson and String message converters
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

        // Make the HTTP POST request, marshaling the request to JSON, and the response to a String
        ResponseEntity<RES> responseEntity = restTemplate.exchange(url, method, requestEntity, reqClass);
        result = responseEntity.getBody();
        long stopMillis = System.currentTimeMillis() - startMillis;

        Log.d(TAG, method + ":" + url + " took " + stopMillis + " ms");
    } catch (Exception e) {
         Log.e(TAG, e.getMessage());
    }
    return result;
}
public class ValidateRequest {
  User user;
  User checkedUser;
  Vehicle vehicle;
}
public class UserResponse {
  User user;
  RequestResult requestResult;
}
public User checkUser(User user, String checkedUserName) {
    String url = urlBuilder()
            .add(USER)
            .add(USER_CHECK)
            .build();

    ValidateRequest request = new ValidateRequest();
    request.setUser(user);
    request.setCheckedUser(new User(checkedUserName));

    UserResponse response = queryRemoteService(url, HttpMethod.POST, request, UserResponse.class);
    return response.getUser();
}
private static <T> ParameterizedTypeReference<BaseResponse<T>> typeReferenceOf ( Class<T> tClass ) {
    return ParameterizedTypeReference.forType( sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make( BaseResponse.class, new Type[]{ tClass }, null ) );
}
@Getter
@Setter
public static class BaseResponse<T> {
    
    private ResponseData<T> response;
    
    public BaseResponse () { }
    
    public boolean hasData () {
        return response != null;
    }

    public T data () {
        return response.data;
    }
    
}

@Getter
@Setter
public static final class ResponseData<T> {
    
    private T data;
    
    public ResponseData () { }
    
}
public <T> Mono <T> get ( URI uri, Class<T> tClass ) {
    
    return webClient
        .get            ()
        .uri            ( uriBuilder        -> uriBuilder.pathSegment( uri.getPath() ).build() )
        .exchangeToMono ( clientResponse    -> clientResponse.bodyToMono( typeReferenceOf( tClass ) ) )
        .flatMap        ( baseResponse      -> baseResponse.hasData() ? Mono.just( baseResponse.data() ) : Mono.empty()  );
    
}