Lambda表達式獲得泛型


Lambda表達式獲得泛型

在使用mybatis-plus的時候會用到lambda表達式構建查詢條件,例如:

LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.<User>lambdaQuery()
				.select(User::getId)
				.eq(User::getId, 1);
List<User> userList = list(lambdaQueryWrapper);

通過Function表達式獲得泛型以及對應的字段,用起來很簡潔方便,公司的項目需要封裝一個公共組件需要實現類似的功能,於是翻看了mybatis-plus的源碼加上一些博客找到了兩種實現方式,記錄一下,僅供參考。

公共的函數式接口

import java.io.Serializable;

/**
 * 支持序列化的 Function
 *
 * @author miemie
 * @since 2018-05-12
 */
@FunctionalInterface
public interface SFunction<T, R> extends Serializable { // 必須繼承 Serializable 接口

	/**
	 * Applies this function to the given argument.
	 *
	 * @param t the function argument
	 * @return the function result
	 */
	R apply(T t);
}

公共的實體類

package com.bart.tests.jdk.lambda;

public class User {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

方式1

SFunction<User, String> object = User::getName;

Class lambdaClass = object.getClass();
Method method = lambdaClass.getDeclaredMethod("writeReplace");
//writeReplace是私有方法,需要去掉私有屬性
method.setAccessible(Boolean.TRUE);
//手動調用writeReplace()方法,返回一個SerializedLambda對象
java.lang.invoke.SerializedLambda lambda = (java.lang.invoke.SerializedLambda) method.invoke(object);

// 獲得類名
String implClass = lambda.getImplClass();
System.out.println(implClass);//com/bart/tests/jdk/User

// 獲得方法明
String implMethodName = lambda.getImplMethodName();
System.out.println(implMethodName);//getName

// 獲得當前接口名
String functionalInterfaceClassName = lambda.getFunctionalInterfaceClass();
System.out.println(functionalInterfaceClassName);//com/bart/tests/jdk/SFunction

方式2

參考mybatis-plus實現方式:

源碼參考位置:com.baomidou.mybatisplus.core.toolkit.LambdaUtils#resolve(com.baomidou.mybatisplus.core.toolkit.support.SFunction)

自定義的SerializedLambda

import java.io.*;

/**
 * 這個類是從 {@link java.lang.invoke.SerializedLambda} 里面 copy 過來的
 * 字段信息完全一樣
 * <p>
 * 負責將一個支持序列的 Function 序列化為 SerializedLambda
 *
 * @author HCL
 * @since 2018/05/10
 */
@SuppressWarnings("unused")
public class SerializedLambda implements Serializable {

    private static final long serialVersionUID = 8025925345765570181L;

    private Class<?> capturingClass;
    private String functionalInterfaceClass;
    private String functionalInterfaceMethodName;
    private String functionalInterfaceMethodSignature;
    private String implClass;
    private String implMethodName;
    private String implMethodSignature;
    private int implMethodKind;
    private String instantiatedMethodType;
    private Object[] capturedArgs;

    /**
     * 獲取接口 class
     *
     * @return 返回 class 名稱
     */
    public String getFunctionalInterfaceClassName() {
        return normalName(functionalInterfaceClass);
    }

    /**
     * 獲取實現的 class
     *
     * @return 實現類
     */
    public Class getImplClass() {
    	try {
            return Class.forName(getImplClassName());
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("找不到指定的class!請僅在明確確定會有 class 的時候,調用該方法", e);
        }
    }

    /**
     * 獲取 class 的名稱
     *
     * @return 類名
     */
    public String getImplClassName() {
        return normalName(implClass);
    }

    /**
     * 獲取實現者的方法名稱
     *
     * @return 方法名稱
     */
    public String getImplMethodName() {
        return implMethodName;
    }

    /**
     * 正常化類名稱,將類名稱中的 / 替換為 .
     *
     * @param name 名稱
     * @return 正常的類名
     */
    private String normalName(String name) {
        return name.replace('/', '.');
    }

    /**
     * @return 字符串形式
     */
    @Override
    public String toString() {
        return String.format("%s -> %s::%s", getFunctionalInterfaceClassName(), getImplClass().getSimpleName(),
            implMethodName);
    }

}

獲得Function泛型信息:

SFunction<User, String> object = User::getName;

if (!object.getClass().isSynthetic()) {
  System.err.println("該方法僅能傳入 lambda 表達式產生的合成類");
  return;
}

// copy mybatis-plus代碼實現 開始 ============
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
oos.close();
byte[] byteArray = baos.toByteArray();

ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(byteArray)) {
  @Override
  protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
    Class<?> clazz = super.resolveClass(objectStreamClass);
    return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
  }
};
// copy mybatis-plus代碼實現 結束 ============
SerializedLambda lambda = (SerializedLambda)objIn.readObject();
objIn.close();

Class implClass = lambda.getImplClass();
System.out.println(implClass);//class com.bart.tests.jdk.User
String implClassName = lambda.getImplClassName();
System.out.println(implClassName);//com.bart.tests.jdk.User
String implMethodName = lambda.getImplMethodName();
System.out.println(implMethodName);//getName
String functionalInterfaceClassName = lambda.getFunctionalInterfaceClassName();
System.out.println(functionalInterfaceClassName);//com.bart.tests.jdk.SFunction

參考資料

參考博客1

參考博客2

mybatis-plus


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM