Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/360.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.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 列表返回类型上具有Rest模板的泛型方法?_Java_Spring_Spring Boot - Fatal编程技术网

Java 列表返回类型上具有Rest模板的泛型方法?

Java 列表返回类型上具有Rest模板的泛型方法?,java,spring,spring-boot,Java,Spring,Spring Boot,我正在尝试创建一个通用的rest模板方法。目标是反序列化为泛型类型,即使该类型已参数化。不幸的是,当我尝试反序列化时,会得到一个哈希映射列表或类似的东西。字体丢失了。这是我们的代码: public List<UserValueDTO> getUserDetails() throws Exception { return getResponse("/user/details"); } private <T> T getResponse(String endpoin

我正在尝试创建一个通用的rest模板方法。目标是反序列化为泛型类型,即使该类型已参数化。不幸的是,当我尝试反序列化时,会得到一个哈希映射列表或类似的东西。字体丢失了。这是我们的代码:

public List<UserValueDTO> getUserDetails() throws Exception {
    return getResponse("/user/details");
}

private <T> T getResponse(String endpoint) throws Exception {
    String token = authenticationService.getToken();
    LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
    headers.add("Authorization",  "Bearer " + token);
    HttpEntity<?> httpEntity = new HttpEntity<>(null, headers);
    try {
        ResponseEntity<T> response = restTemplate.exchange(baseUrl + endpoint,
                HttpMethod.GET, httpEntity, new ParameterizedTypeReference<T> {});
        return response.getBody();
    } catch (HttpClientErrorException ex) {
        throw new Exception("Unable to get a response from service");
    }
}
public List getUserDetails()引发异常{
返回getResponse(“/user/details”);
}
私有T getResponse(字符串端点)引发异常{
String token=authenticationService.getToken();
LinkedMultiValueMap头=新建LinkedMultiValueMap();
添加(“授权”、“承载人”+令牌);
HttpEntity HttpEntity=新的HttpEntity(空,标题);
试一试{
ResponseEntity response=restemplate.exchange(baseUrl+endpoint,
HttpMethod.GET,httpEntity,新的参数化类型引用{});
返回response.getBody();
}捕获(HttpClientErrorException-ex){
抛出新异常(“无法从服务获取响应”);
}
}
我们还编写了一个自动测试来揭示问题。这是测试

@Test
public void requestUserDetails_getsUserDetailsFromExternalService() throws Exception {
    doReturn("abcdefg-123456").when(mockAuthenticationService).getToken();

    server.expect(requestTo("http://localhost:8090/user/details"))
            .andExpect(method(HttpMethod.GET))
            .andExpect(header("Authorization", "Bearer abcdefg-123456"))
            .andRespond(withSuccess("[\n" +
                    "  {\n" +
                    "    \"userId\": 12345,\n" +
                    "    \"value\": 500.0\n" +
                    "  },\n" +
                    "  {\n" +
                    "    \"userId\": 5555,\n" +
                    "    \"value\": 300.0\n" +
                    "  }\n" +
                    "]", MediaType.APPLICATION_JSON));

    List<UserValueDTO> userValueDTOs = accountServiceClient.getUserDetails();

    assertThat(userValueDTOs).containsExactlyInAnyOrder(
            new UserValueDTO.Builder().userId(12345).value(500.0).build(),
            new UserValueDTO.Builder().userId(5555).value(300.0).build()
    );
}
@测试
public void requestUserDetails\u GetSuserDetails RomexternalService()引发异常{
doReturn(“abcdefg-123456”).when(mockAuthenticationService).getToken();
expect(requestTo)(“http://localhost:8090/user/details"))
.andExpect(方法(HttpMethod.GET))
.andExpect(标题(“授权”、“持有人abcdefg-123456”))
.andRespond(成功(“[\n”)+
“{\n”+
“用户ID”:12345\n+
“\“值\”:500.0\n”+
},\n+
“{\n”+
“用户ID”:5555\n+
“\“值\”:300.0\n”+
“}\n”+
“]”,MediaType.APPLICATION_JSON));
List userValueDTOs=accountServiceClient.getUserDetails();
assertThat(userValueDTOs).在Yorder中实际包含(
新的UserValueDTO.Builder().userId(12345).value(500.0).build(),
新建UserValueDTO.Builder().userId(5555).value(300.0).build()
);
}
针对此代码运行此测试的结果为:

java.lang.AssertionError: 
Expecting:
   <[{"userId"=12345, "value"=500.0}, {"userId"=5555, "value"=300.0}]>
to contain exactly in any order:
   <[com.project.dto.UserValueDTO@408516e7,
     com.project.dto.UserValueDTO@407560ad]>
elements not found:
  <[com.project.dto.UserValueDTO@408516e7,
    com.project.dto.UserValueDTO@407560ad]>
and elements not expected:
  <[{"userId"=12345, "value"=500.0}, {"userId"=5555, "value"=300.0}]>
java.lang.AssertionError:
期望:
以任何顺序完全包含:
未找到元素:
以及不预期的因素:

反序列化时,有没有办法不丢失列表上的参数化类型?谢谢

根据我们在评论中的交流,问题是如何使用
新的ParameterizedTypeReference(){}
。这不起作用的原因与这些类型标记/类型引用/等对象的工作方式有关。(Neal Gafter的博客文章最初对此进行了描述。)

抽象类TypeRefExample{
最终类型typeOfT;
TypeRefExample(){
//获取扩展子类。
//(通常是一个匿名类,如TypeRefExample(){}。)
Class subclass=getClass();
//获取泛型超类,它是
//在扩展条款中。
//这可以是明确的,如:
//类FooTypeRef扩展了TypeRefExample{}
//或者在匿名类的情况下是隐式的:
//新的TypeRefExample(){}
//它声明了一个类,类似于:
//类OuterClass$1扩展了TypeRefExample{}
类型superclass=subclass.getGenericSuperclass();
//如果超类是参数化类型
//可以检索其类型参数。
typeOfT=((参数化类型)超类)
.getActualTypeArguments()[0];
//真正的实现应该做更多的工作
//工作,但这是最基本的想法。
}
}
因此,如果您有一个
新的ParameterizedTypeReference(){}
,则
getClass().getGenericSuperclass()
返回隐式extends子句中的类型,即
ParameterizedTypeReference
,其类型参数是类型变量
T

如果使用此
参数化TypeReference
对于使测试正常工作至关重要,那么很遗憾,您必须将其作为参数传入。必须使用实际类型参数
新建ParameterizedTypeReference(){}
创建它


Guava对解析类上声明的类型变量有一些建议,但对方法上声明的类型变量也有一些建议,实际上是不可能的,因为在调用站点无法将类型参数具体化为方法。

我帮不上忙,因为我不知道Spring,但是
newparametedtypereference{}
在我看来非常可疑,因为我知道这样的类是如何工作的。这不会创建
参数化类型引用
。它将创建一个
ParameterizedTypeReference
,其类型参数是
java.lang.reflect.TypeVariable
的实例,该实例由方法
getResponse
声明。尝试
System.out.println(新的参数化类型引用{}.getType())明白我的意思。@Radiodef-Yikes。上面说类型是“T”。那不好。这里有没有其他方法来获取泛型的参数化类型?不幸的是,您必须将其作为参数传递给方法。你必须用你想要的实际类型参数来实例化
ParameterizedTypeReference
,比如
new ParameterizedTypeReference(){}
@Radiodef这不是世界上最漂亮的东西,但它正是我们要找的!谢谢有一个问题,您的泛型方法是否应该具有类似私有列表getResponse(字符串端点)的签名,并因此使用List而不是ResponseEntity和ParameteredTypeReference?
abstract class TypeRefExample<T> {
    final Type typeOfT;

    TypeRefExample() {
        // Get the extending subclass.
        // (Usually an anonymous class like TypeRefExample<String>() {}.)
        Class<?> subclass = getClass();
        // Get the generic superclass, which is the type
        // in the extends clause.
        // This can be explicit like:
        //  class FooTypeRef extends TypeRefExample<Foo> {}
        // or implicit as in the case of an anonymous class:
        //  new TypeRefExample<Foo>() {}
        // which declares a class something like:
        //  class OuterClass$1 extends TypeRefExample<Foo> {}
        Type superclass = subclass.getGenericSuperclass();
        // Then if the superclass is a ParameterizedType
        // its type argument can be retrieved.
        typeOfT = ((ParameterizedType) superclass)
                    .getActualTypeArguments()[0];
        // A real implementation should do some more
        // work but that's the basic idea.
    }
}