2016-08-25 67 views
0

我想学习使用泛型的第一次,一个相当复杂的方式为返回类型最佳实践。我也使用Jackson 2进行反序列化。什么是使用Java泛型和工厂模式

我在我的return语句每次铸造。有人能告诉我这是错的吗?如果是这样,有什么更好的方法来做到这一点?

下面是一个简单的例子类,演示了这种情况:

class ResourceFactory <T extends Resource>{ 

    List<T> getResources(String path) 
    { 
     ResourcesResponse rgRes = new ObjectMapper() 
     .readValue(response.body().byteStream(), ResourcesResponse.class) 

     return (List<T>)rgRes.resources 
    } 
} 

UPDATE:
每一个评论,这里是另一类机构是什么样的超简化的例子。

class ResourceResponse { 
    List<Resource> resources 
} 

class ResourceGeneric extends Resource { 
} 

class ResourceTypeOne extends Resource { 
    public String typeOneOnlyProperty 
} 

class ResourceTypeTwo extends Resource { 
    public String typeTwoOnlyProperty 
} 
+1

您可以分享“ResourcesResponse”和“Resource”的定义吗? –

+0

我已经添加了一些模拟。如果你想看杰克逊的注释,我也可以嘲笑这些,但是杰克逊的反序列化没有问题。我只是想确定在每个回报声明中投出(列表)是否最好。 – solvingJ

+0

'ResourceResponse'应该是'ResourceResponse '。资源应该是'List '。你应该传递一个TypeReference >作为参数。 –

回答

3

如果正确使用杰克逊可以支持泛型类型。以下是我的做法:

class ResourcesResponse<T extends Resource> { 
    List<T> resources; 
} 

class ResourceFactory<T extends Resource> { 
    // Either of these should work; pick your constructor 
    private JavaType responseType; 
    private TypeReference<ResourcesResponse<T>> responseType; 

    // Option A 
    // Involves some boilerplate, but keeps the constructor simple 
    // Use: new ResourceFactory<ResourceTypeOne>(ResourceTypeOne.class) 
    ResourceFactory(Class<T> resourceType) { 
     this.responseType = TypeFactory.defaultInstance() 
       .constructParametricType(ResourcesResponse.class, resourceType); 
    } 

    // Option B 
    // Cleaner internally, but exposes implementation details 
    // Use: new ResourceFactory<ResourceTypeOne>(new TypeReference<ResourcesResponse<ResourceTypeOne>>() {}) 
    ResourceFactory(TypeReference<ResourcesResponse<T>> responseType) { 
     this.responseType = responseType; 
    } 

    List<T> getResources(String path) 
    { 
     ResourcesResponse<T> rgRes = new ObjectMapper() 
     .readValue(response.body().byteStream(), responseType); 

     return rgRes.resources; 
    } 
} 
+0

感谢您的回答。仍在阅读。你的意思是把这个变量命名为别的:private TypeReference > responseType; – solvingJ

+0

它看起来像你的方法的主要区别在于你需要一个类名作为参数传入parens(),而不是通过箭头<>传入类型信息。我猜测这是唯一能够告诉杰克逊究竟是什么类反序列化为动态的东西(只有“T”符号才能做到的事情)。这实际上对我特别有用,因为我收到了一些JSON响应中没有包含类型的良好指示的情况,所以我必须编写一个选择器并传入一个类名。这对我有很大的帮助。 – solvingJ

+0

选择这个作为最佳答案,因为它也解释了我的场景中的杰克逊组件。很彻底!非常感谢你! – solvingJ

1

因为类型擦除的快速失败的技术是通过资源子类:

public <T extends Resource> List<T> getResources(Class<T> resourceType, String path) 
{ 
    ResourcesResponse rgRes = new ObjectMapper() 
    .readValue(response.body().byteStream(), ResourcesResponse.class) 

    return Collections.checkedList(rgRes.resources, resourceType); 
} 

这将确保这样的不安全类型转换的代码有没有其他类的值被添加。

这不“检查”原始列表

rgRes.resources.forEach(res -> resourceType.cast(res)) 

而且这不是一个简单的铸件。

+0

我明白了你的观点,实际上我正在努力实现JB Nizets的评论,即上行并将ResourceResponse更改为ResourceResponse ,并将List 中的资源更改为List 。 .....后续问题,“List ”部分从来不适用于我的方法,我似乎只能在课堂上使用。它表示它在T之后期待>,另外还有三条红线出现。任何想法我做错了什么? – solvingJ

+0

实施例:这是不对的定义:公共类盒{ 公共列表检查(T t)的{ } } – solvingJ

+0

我在仿制药部分的错误,所以做:'公共列表检查(...)' –