JAVA泛型类的使用

首先说说我用到的应用场景:

需求描述:

在工作流(workflow)中,存在着各种各样的工作流程,这些流程呢有一些特征——1.流程基本信息相同 2.流程内容不同

在给前端写接口请求实体的时候,在我接手功能之前是将流程内容实体作为流程属性放在请求实体内,导致不同的流程要写不同的请求实体,违背了开闭原则。

我第一个想到的方案是泛型。

下面是方案——————————————————

流程实体(ApplyEntity ):

/**
 * Created by xmtx on 2018/9/8.
 */
public class ApplyEntity {
    /**
     * 流程id
     */
    private String applyId;
    /**
     * 流程名称
     */
    private String applyName;
    /**
     * 流程类型
     */
    private Integer applyType;
    /**
     * 流程基本信息
     */
    private String applyBaicInfo;


    public String getApplyId() {
        return applyId;
    }

    public void setApplyId(String applyId) {
        this.applyId = applyId;
    }

    public String getApplyName() {
        return applyName;
    }

    public void setApplyName(String applyName) {
        this.applyName = applyName;
    }

    public String getApplyBaicInfo() {
        return applyBaicInfo;
    }

    public void setApplyBaicInfo(String applyBaicInfo) {
        this.applyBaicInfo = applyBaicInfo;
    }

    public Integer getApplyType() {
        return applyType;
    }

    public void setApplyType(Integer applyType) {
        this.applyType = applyType;
    }

    @Override
    public String toString() {
        return "ApplyEntity{" +
                "applyId='" + applyId + '\'' +
                ", applyName='" + applyName + '\'' +
                ", applyType=" + applyType +
                ", applyBaicInfo='" + applyBaicInfo + '\'' +
                '}';
    }

流程内容 类型一(职位):

/**
 * 岗位信息
 * Created by xmtxon 2018/9/3.
 */
public class PostInfo extends BaseEntity{
    // 岗位编码
    private String postCode;
    // 岗位名称
    private String postName;

    public String getPostCode() {
        return postCode;
    }

    public void setPostCode(String postCode) {
        this.postCode = postCode;
    }

    public String getPostName() {
        return postName;
    }

    public void setPostName(String postName) {
        this.postName = postName;
    }

    @Override
    public String toString() {
        return "PostInfo{" +
                "postCode='" + postCode + '\'' +
                ", postName='" + postName + '\'' +
                '}';
    }

流程内容 类型二 (报表):

/**
 * @Author: xmtx
 * @Description: report
 * @Date: Created by xmtxon 2018/9/8.
 */
public class RptBaseDto {

    //报表Id
    private String reportId;
    //报表版本id
    private String versionId;

    public RptBaseDto() {
        // this is a construct
    }

    public RptBaseDto(String reportId, String versionId) {
        this.reportId = reportId;
        this.versionId = versionId;
    }

    public String getReportId() {
        return reportId;
    }

    public void setReportId(String reportId) {
        this.reportId = reportId;
    }

    public String getVersionId() {
        return versionId;
    }

    public void setVersionId(String versionId) {
        this.versionId = versionId;
    }

    /*@Override
    public String toString() {
        return reportId + '_' + versionId;
    }*/

}

请求参数 泛型类:

/**
 * Created by xmtx on 2018/9/8.
 */
public class ApplyRequest<T> extends ApplyEntity{

    /**
     * 泛型属性,作为流程内容
     */
    private T  applyContent;

    public T getApplyContent() {
        return applyContent;
    }

    public void setApplyContent(T applyContent) {
        this.applyContent = applyContent;
    }

    @Override
    public String toString() {
        return "ApplyRequest{" +
                "applyContent=" + applyContent +
                '}';
    }

到此为止,请求参数泛型类已经满足功能需求,我们有新增的流程,只需要创建新的流程内容实体即可。

下面要解决的是前后台参数序列化的问题:

我们先构造两种类型的请求参数:

  public static void main(String[] args) {

        //流程基本信息
        ApplyRequest applyRequest = new ApplyRequest();
        applyRequest.setApplyId("2333");
        applyRequest.setApplyName("applyName");
        applyRequest.setApplyType(1);
        applyRequest.setApplyBaicInfo("basic infomation");

        /**
         * 流程内容 类型一:岗位信息
         */
        PostInfo postInfo = new PostInfo();
        postInfo.setPostCode("postCode");
        postInfo.setPostName("postName");

        applyRequest.setApplyContent(postInfo);
        System.out.println("=============流程内容一:岗位================");
        System.out.println(JSON.toJSONString(applyRequest));

        /**
         * 流程内容 类型二 :报表信息
         */
        RptBaseDto reportEntity = new RptBaseDto();
        reportEntity.setReportId("reportId");
        reportEntity.setVersionId("versionid");
        applyRequest.setApplyType(2);
        applyRequest.setApplyContent(reportEntity);
        System.out.println("=============流程内容二:报表================");

        System.out.println(JSON.toJSONString(applyRequest));


    }

得到的结果如下:

=============流程内容一:岗位================
{"applyBaicInfo":"basic infomation","applyContent":{"id":0,"postCode":"postCode","postName":"postName"},"applyId":"2333","applyName":"applyName","applyType":1}
=============流程内容二:报表================
{"applyBaicInfo":"basic infomation","applyContent":{"reportId":"reportId","versionId":"versionid"},"applyId":"2333","applyName":"applyName","applyType":2}

编写post请求方法,在wagger或者postman中模拟post请求。

 @RequestMapping(value = "/testFX", method = RequestMethod.POST)
    public ResponseObject testFX(@RequestBody ApplyRequest applyRequest) {
        System.out.println(JSON.toJSONString(applyRequest));
        Integer applyType = applyRequest.getApplyType();
        String instance = JSON.toJSONString(applyRequest);
        switch (applyType){
            case 1:
                ApplyRequest<PostInfo> applyRequest1 = applyRequest;
                PostInfo postInfo = applyRequest1.getApplyContent();
                return new ResponseObject(JSON.toJSONString(postInfo));
            case 2:
                ApplyRequest<RptBaseDto> applyRequest2 = applyRequest;
                RptBaseDto rptBaseDto = applyRequest2.getApplyContent();
                return new ResponseObject(JSON.toJSONString(rptBaseDto));
            default:
                return null;
        }
    }

测试方法,于是我们得到了如下异常:

{
  "statusCode": "100000",
  "msg": "系统未知异常",
  "error": "java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.suning.drp.common.applicationcenter.bean.PostInfo"
}

于是乎,我们进入debug模式:

我们看到参数被序列化成LinkedHashMap[],看来Spring MVC 的 @RequestBody 并不能将泛型参数反序列化。

我们于是找google爸爸(Casting LinkedHashMap to Complex Object)。

解决方案如下:

POJO pojo = mapper.convertValue(singleObject, POJO.class);
// or:
List<POJO> pojos = mapper.convertValue(listOfObjects, new TypeReference<List<POJO>>() { });

于是改变代码为:

 @RequestMapping(value = "/testFX", method = RequestMethod.POST)
    public ResponseObject testFX(@RequestBody ApplyRequest applyRequest) {
        System.out.println(JSON.toJSONString(applyRequest));
        Integer applyType = applyRequest.getApplyType();
        String instance = JSON.toJSONString(applyRequest);
        switch (applyType){
            case 1:
                PostInfo postInfo = mapper.convertValue(applyRequest.getApplyContent(), PostInfo.class);
                return new ResponseObject(JSON.toJSONString(postInfo));
            case 2:
                ApplyRequest<RptBaseDto> applyRequest2 = applyRequest;
                RptBaseDto rptBaseDto = applyRequest2.getApplyContent();
                return new ResponseObject(JSON.toJSONString(rptBaseDto));
            default:
                return null;
        }
    }

但得到的结果却不是我们想要的:

问题在哪里呢,我们稍后再分析,先给出解决方案:

我们先把请求参数转换为JSONString ,然后再转换为泛型对实体(这样就完美解决了fastjson的不足):

@RequestMapping(value = "/testFX", method = RequestMethod.POST)
public ResponseObject testFX(@RequestBody ApplyRequest applyRequest) {
    Integer applyType = applyRequest.getApplyType();
    String instance = JSON.toJSONString(applyRequest);

    switch (applyType) {
        case 1:
            ApplyRequest<PostInfo> postInfo1 = JSON.parseObject(instance, ApplyRequest.class);
            //do something
            return new ResponseObject(JSON.toJSONString(postInfo1));
        case 2:
            ApplyRequest<RptBaseDto> applyRequest2 = JSON.parseObject(instance, ApplyRequest.class);
            //do something
            return new ResponseObject(JSON.toJSONString(applyRequest2));
        default:
           return new ResponseObject("error");
    }
}

关于泛型的其它应用场景可参考csdn的这篇(https://blog.csdn.net/u011240877/article/details/53545041),谢谢您的阅读。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券