转载

记一次lombok的问题

一、案发现场

此问题的案发现场是测试环境,为了减少不必要的类,我们这里用一个简单的例子进行模拟。

lombok version:1.16.14

jdk version:1.8

上代码:

<!-- more -->

├─src
│  ├─main
│  │  ├─java
│  │  │  └─org
│  │  │      └─jsbxyyx
│  │  │          └─util
│  │  │                  DozerUtil.java
│  │  │
│  │  └─resources
│  └─test
│      ├─java
│      │  └─org
│      │      └─jsbxyyx
│      │          └─test
│      │                  A.java
│      │                  A1.java
│      │                  DozerTest.java
│      │
│      └─resources
package org.jsbxyyx.util;

import com.google.common.collect.Lists;
import org.dozer.DozerBeanMapper;
import java.util.Collection;
import java.util.List;

public class DozerUtil {
    private static DozerBeanMapper dozer = new DozerBeanMapper();

    public static <T> T map(Object source, Class<T> destinationClass) {
        return dozer.map(source, destinationClass);
    }
    public static <T> List<T> mapList(@SuppressWarnings("rawtypes") Collection sourceList, Class<T> destinationClass) {
        List<T> destinationList = Lists.newArrayList();
        for (Object sourceObject : sourceList) {
            T destinationObject = dozer.map(sourceObject, destinationClass);
            destinationList.add(destinationObject);
        }
        return destinationList;
    }
    public static void map(Object source, Object destinationObject) {
        dozer.map(source, destinationObject);
    }
}
package org.jsbxyyx.test;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@ToString
public class A {
    private String date;
    private String vNum;
}
package org.jsbxyyx.test;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@ToString
public class A1 {
    private String date;
    private String vaNum;
}
package org.jsbxyyx.test;

import java.util.HashMap;
import java.util.Map;
import org.jsbxyyx.util.DozerUtil;
import org.junit.Assert;
import org.junit.Test;

public class DozerTest {
    
    @Test
    public void testA() throws Exception {
        Map<String, String> mapA = new HashMap<>();
        mapA.put("date", "2018-04-03");
        mapA.put("vNum", "123");
        A a = DozerUtil.map(mapA, A.class);
        Assert.assertEquals("123", a.getVNum());
    }
    
    @Test
    public void testA1() throws Exception {
        Map<String, String> mapA1 = new HashMap<>();
        mapA1.put("date", "2018-04-03");
        mapA1.put("vaNum", "123");
        A1 a = DozerUtil.map(mapA1, A1.class);
        Assert.assertEquals("123", a.getVaNum());
    }
}

二、案件分析

我们执行测试用testA和testA1发现

testA 红了

testA1 绿了

红了表示测试不通过啊。。。。。我们来看看为啥不通过。

问题的关键在于lombok生成getter,setter的时候没有按照JavaBean的规范来生成。导致testA就红了。

直接看反编译代码:

A.class

记一次lombok的问题

我们再看看eclipse或者idea生成getter,setter是怎么样的

记一次lombok的问题

到了这里,我们发现问题了,lombok的getter,setter方法生成的不对。

三、案件处理

解决办法,去掉@Getter @Setter注解,用IDE生成,获取覆盖相应的getter/setter

四、案件原理追溯

那么我们来分析一下,标准JavaBean是如何生成的。

官方文档: Java Beans specification

看到英语头大有木有。。。有木有。。。有木有。。。

好我们解释一下。

首先我们来描述一下JavaBean的规范

  1. Bean有一个默认的无参构造器
  2. 属性修饰符为private
  3. 实现接口java.io.Serializable
  4. 所有的访问器都以get开头,所有的修改器都用set,布尔类型访问器用is开头

接下来我们来说一下javabean的getters/setters是如何生成,也就解决了问题。。

这个类Introspector.decapitalize()方法,可以获取到属性

Utility method to take a string and convert it to normal Java variable name capitalization.  This normally means converting the first character from upper case to lower case, but in the (unusual) special case when there is more than one character and both the first and second characters are upper case, we leave it alone.

Thus "FooBah" becomes "fooBah" and 
"X" becomes "x", 
but "URL" stays as "URL".

意思就是第一个字母转大写后,如果第二个字母和转换后的第一个字母一样是大写,那么就返回原值。否则就返回首字母大写后的值。

问题就到这里啦。。。。。。。

原文地址: https://blog.uyiplus.com/2018/lombok-quesion-1/

原文  https://segmentfault.com/a/1190000014420052
正文到此结束
Loading...