我有一个没有泛型定义的方法,如下所示:
private void methodWithoutGenerics(Integer subjectKey) {
Client client = AuthClient.create();
List<JsonResult> clinicalItems = client
.resource(getBaseUrl() + "/rest/v1/patients/" + subjectKey + "/" + "results")
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(new GenericType<List<JsonResult>>() {
});
assertFalse(clinicalItems.isEmpty());
JsonResult clinicalItem = client
.resource(getBaseUrl() + "/rest/v1/patients/" + subjectKey + "/" + "results" + "/" + clinicalItems.get(0).getClinicalItemKey())
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(new GenericType<JsonResult>() {
});
assertNotNull(clinicalItem);
}
这段代码可以正常工作,但是我希望能够使用不同的类型来调用它:
methodWithGenerics(subjectKey, "results", JsonResult.class);
methodWithGenerics(subjectKey, "medications", JsonMedication.class);
methodWithGenerics(subjectKey, "allergies", JsonAllergy.class);
而且我想不出一种方法来泛化上述方法,以使其与该签名一起“起作用”。我担心我必须将输入内容复制并粘贴三遍。
右侧的所有这些类都有一个名为
JsonClinicalItem
的基类。它具有一种称为“ cc”的临床项目的方法。我该如何概括呢?可能吗
这是我尝试过的:
private <T extends JsonClinicalItem> void methodWithGenerics(Integer subjectKey, String pluralName, Class<T> t) {
Client client = AuthClient.create();
List<T> clinicalItems = client
.resource(getBaseUrl() + "/rest/v1/patients/" + subjectKey + "/" + pluralName)
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(new GenericType<List<T>>() {
});
assertFalse(clinicalItems.isEmpty());
T clinicalItem = client
.resource(getBaseUrl() + "/rest/v1/patients/" + subjectKey + "/" + pluralName + "/" + clinicalItems.get(0).getClinicalItemKey())
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(new GenericType<T>() {
});
assertNotNull(clinicalItem);
}
这样可以编译,但是当我运行代码时,
getClinicalItemKey()
会引发类强制转换异常。因此,很明显,我编写此通用方法的方式与原始方法的外观有所不同。话虽如此,我已经比较了两个调用之间的服务器输出,它们是相同的。这是堆栈跟踪:java.lang.ClassCastException: java.lang.reflect.Method cannot be cast to java.lang.Class
at com.owlike.genson.reflect.TypeUtil.getTypes(TypeUtil.java:362)
at com.owlike.genson.reflect.TypeUtil.match(TypeUtil.java:298)
at com.owlike.genson.convert.BasicConvertersFactory.provide(BasicConvertersFactory.java:102)
at com.owlike.genson.convert.BasicConvertersFactory.create(BasicConvertersFactory.java:74)
at com.owlike.genson.convert.BasicConvertersFactory.create(BasicConvertersFactory.java:56)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
at com.owlike.genson.convert.CircularClassReferenceConverterFactory.create(CircularClassReferenceConverterFactory.java:58)
at com.owlike.genson.convert.CircularClassReferenceConverterFactory.create(CircularClassReferenceConverterFactory.java:22)
at com.owlike.genson.Genson.provideConverter(Genson.java:182)
at com.owlike.genson.convert.DefaultConverters$CollectionConverterFactory.create(DefaultConverters.java:115)
at com.owlike.genson.convert.DefaultConverters$CollectionConverterFactory.create(DefaultConverters.java:106)
at com.owlike.genson.convert.BasicConvertersFactory.provide(BasicConvertersFactory.java:102)
at com.owlike.genson.convert.BasicConvertersFactory.create(BasicConvertersFactory.java:74)
at com.owlike.genson.convert.BasicConvertersFactory.create(BasicConvertersFactory.java:56)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:93)
at com.owlike.genson.convert.ChainedFactory.create(ChainedFactory.java:80)
at com.owlike.genson.convert.CircularClassReferenceConverterFactory.create(CircularClassReferenceConverterFactory.java:58)
at com.owlike.genson.convert.CircularClassReferenceConverterFactory.create(CircularClassReferenceConverterFactory.java:22)
at com.owlike.genson.Genson.provideConverter(Genson.java:182)
at com.owlike.genson.Genson.deserialize(Genson.java:330)
at com.owlike.genson.ext.jersey.GensonJsonConverter.readFrom(GensonJsonConverter.java:124)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:565)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:535)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:696)
at com.sun.jersey.api.client.WebResource.access$300(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:512)
at com.mirth.results.rest.resource.UrlsWorkIntegrationTest.methodWithGenerics(UrlsWorkIntegrationTest.java:114)
at com.mirth.results.rest.resource.UrlsWorkIntegrationTest.canTraverseUrls(UrlsWorkIntegrationTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
这是错误的,说:
List<T> clinicalItems = client
.resource(getBaseUrl() + "/rest/v1/patients/" + subjectKey + "/" + pluralName)
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(new GenericType<List<T>>() {
});
如果运行
methodWithGenerics(subjectKey, "results", JsonResult.class);
,则不会发生此错误。因此,两者之间的泛型必须存在一些我不了解的差异。该代码正在使用Jersey。我认为这没关系,因为我的“ withoutGenerics”方法可以正常工作,所以这可能不是泽西岛的问题。但是这是我对Jersey的依赖:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.17</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server-linking</artifactId>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.17.1</version>
</dependency>
最佳答案
GenericType
通过查看自己的类声明来工作,并从其自己的类声明中获取泛型超类型的参数。当您创建诸如new GenericType<List<JsonResult>>() { }
这样的匿名类时,该类的超类型为GenericType<List<JsonResult>>
,并且此声明信息存储在字节码中,并且可以在运行时进行检索,并且可以从中获取List<JsonResult>
。
这意味着,如果您创建像这样的new GenericType<List<T>>() { }
匿名类,则它实际上会从中获得List<T>
。不是List<Something>
;只是List<T>
,因为这是声明类的方式。在这里,T
仅被视为某些类型参数。换句话说,要使GenericType
的子类化技巧起作用,必须在编译时对类型信息进行硬编码。
那么,如果您的函数必须对多种类型之一执行此操作,会发生什么情况呢?正如您所发现的,一种解决方案是让调用者传递经过适当构造的GenericType
对象。调用者可能会通过使用具有硬编码类型的子类来获得它(大概每个调用位置只需要对一种类型执行此操作,因此可以对其进行硬编码)。
另一种方法是在运行时自己真正构造GenericType
对象。 com.sun.jersey.api.client.GenericType
类提供了第二个构造函数,该构造函数带有Type
参数,该参数允许您基于该类型创建GenericType
。 Type
表示Java中的任何通用或非通用类型。对于非泛型类型,只需使用类对象:
T clinicalItem = client
.resource(getBaseUrl() + "/rest/v1/patients/" + subjectKey + "/" + pluralName + "/" + clinicalItems.get(0).getClinicalItemKey())
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(new GenericType<T>(t));
对于泛型类型,您必须进行一些实现
ParameterizedType
接口的操作。您可以实现自己的类来执行此操作,也可以将现有的实现置于某处,但是我将只展示一个简化的版本:List<T> clinicalItems = client
.resource(getBaseUrl() + "/rest/v1/patients/" + subjectKey + "/" + pluralName)
.accept(MediaType.APPLICATION_JSON_TYPE)
.get(new GenericType<List<T>>(new ParameterizedType() {
public Type[] getActualTypeArguments() { return new Type[]{t}; }
public Type getRawType() { return List.class; }
public Type getOwnerType() { return null; }
}));