Lambda方式获取属性信息

862 阅读5分钟

SerializedLambda

在java 8中,如果函数式接口实现了Serializable,那这个函数式接口用lambda表达式实现时,编译后的函数式接口的实现类,会有一个私有的“writeReplace”方法,返回 SerializedLambda 对象。而 SerializedLambda 这个类,包含了函数式接口和实现方法等的信息。 方法:

  • serializedLambda.getImplMethodName(),获取实现方法的名称。如果是直接传递的方法引用,则获取的就是引用的方法的名称
  • serializedLambda.getImplClass(),获取实现方法所在的类的全限定名,用过“/”连接的字符串。如果是直接传递的方法引用,就能获取引用的方法所在类的名称

实现了Serializable接口的Function函数

@FunctionalInterface
public interface SFunction<T, R> extends Function<T, R>, Serializable {
}
package com.fxin.lambda;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class FieldUtil {
    /**
     * 将bean的属性的get方法,作为lambda表达式传入时,获取get方法对应的属性Field
     *
     * @param fn  lambda表达式,bean的属性的get方法
     * @param <T> 泛型
     * @return 属性对象
     */
    public static <T> Field getField(SFunction<T, ?> fn) {
        // 从function取出序列化方法
        Method writeReplaceMethod;
        try {
            writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        // 从序列化方法取出序列化的lambda信息
        boolean isAccessible = writeReplaceMethod.isAccessible();
        writeReplaceMethod.setAccessible(true);
        SerializedLambda serializedLambda;
        try {
            serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(fn);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        } finally {
            writeReplaceMethod.setAccessible(isAccessible);
        }

        // 从lambda信息取出method、field、class等
        String implMethodName = serializedLambda.getImplMethodName();
        // 确保方法是符合规范的get方法,boolean类型是is开头
        if (!implMethodName.startsWith("is") && !implMethodName.startsWith("get")) {
            throw new RuntimeException("get方法名称: " + implMethodName + ", 不符合java bean规范");
        }

        // get方法开头为 is 或者 get,将方法名 去除is或者get,然后首字母小写,就是属性名
        int prefixLen = implMethodName.startsWith("is") ? 2 : 3;

        String fieldName = implMethodName.substring(prefixLen);
        String firstChar = fieldName.substring(0, 1);
        fieldName = fieldName.replaceFirst(firstChar, firstChar.toLowerCase());
        Field field;
        try {
            field = Class.forName(serializedLambda.getImplClass().replace("/", ".")).getDeclaredField(fieldName);
        } catch (ClassNotFoundException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }

        return field;
    }

}

被测试对象

package com.fxin.netty.entity;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;

/**
 *
 * This class was generated by MyBatis Generator.
 * This class corresponds to the database table user
 */
@Table(name="user")
public class UserEntity {
    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.id
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    @Id
    private String id;

    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.username
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    private String username;

    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.password
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    private String password;

    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.face_image
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    @Column(name = "face_image")
    private String faceImage;

    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.face_image_big
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    @Column(name = "face_image_big")
    private String faceImageBig;

    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.nick_name
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    private String nickName;

    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.qrcode
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    private String qrcode;

    /**
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column user.cid
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    private String cid;

    private Date currentDate;

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.id
     *
     * @return the value of user.id
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getId() {
        return id;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.id
     *
     * @param id the value for user.id
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setId(String id) {
        this.id = id == null ? null : id.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.username
     *
     * @return the value of user.username
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getUsername() {
        return username;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.username
     *
     * @param username the value for user.username
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setUsername(String username) {
        this.username = username == null ? null : username.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.password
     *
     * @return the value of user.password
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getPassword() {
        return password;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.password
     *
     * @param password the value for user.password
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.face_image
     *
     * @return the value of user.face_image
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getFaceImage() {
        return faceImage;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.face_image
     *
     * @param faceImage the value for user.face_image
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setFaceImage(String faceImage) {
        this.faceImage = faceImage == null ? null : faceImage.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.face_image_big
     *
     * @return the value of user.face_image_big
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getFaceImageBig() {
        return faceImageBig;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.face_image_big
     *
     * @param faceImageBig the value for user.face_image_big
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setFaceImageBig(String faceImageBig) {
        this.faceImageBig = faceImageBig == null ? null : faceImageBig.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.nick_name
     *
     * @return the value of user.nick_name
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getNickName() {
        return nickName;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.nick_name
     *
     * @param nickName the value for user.nick_name
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setNickName(String nickName) {
        this.nickName = nickName == null ? null : nickName.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.qrcode
     *
     * @return the value of user.qrcode
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getQrcode() {
        return qrcode;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.qrcode
     *
     * @param qrcode the value for user.qrcode
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setQrcode(String qrcode) {
        this.qrcode = qrcode == null ? null : qrcode.trim();
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method returns the value of the database column user.cid
     *
     * @return the value of user.cid
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public String getCid() {
        return cid;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method sets the value of the database column user.cid
     *
     * @param cid the value for user.cid
     *
     * @mbg.generated Wed Nov 24 22:37:18 CST 2021
     */
    public void setCid(String cid) {
        this.cid = cid == null ? null : cid.trim();
    }

    public Date getCurrentDate() {
        return currentDate;
    }

    public void setCurrentDate(Date currentDate) {
        this.currentDate = currentDate;
    }
}

测试类

package com.fxin.lambda;

import com.fxin.netty.entity.UserEntity;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

import static com.fxin.lambda.FieldUtil.*;

public class TestLambda {
    public static void main(String[] args) {
        Field field = getField(UserEntity::getCurrentDate);
        System.out.println(field);

        // 字段名称
        String fieldName = field.getName();
        System.out.println(fieldName);

        // 字段上面的注解
        Annotation[] annotations = field.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        // 字段的类型
        Class<?> type = field.getType();
        System.out.println(type);
    }
}