Last active
August 6, 2020 15:23
-
-
Save qbosen/e4cbdd18c22ffb5686c306476cd0748d to your computer and use it in GitHub Desktop.
从方法引用获取属性字面值
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package top.abosen.nameware; | |
import java.io.Serializable; | |
import java.lang.invoke.SerializedLambda; | |
import java.lang.reflect.Method; | |
import java.util.Arrays; | |
import java.util.Optional; | |
public class Main { | |
public static void main(String[] args) { | |
System.out.println(NameAware.nameOf(Person::getAge)); | |
System.out.println(NameAware.nameOf(Person::setName)); | |
System.out.println(NameAware.nameOf(Person::isMale)); | |
// error: not a getter method | |
System.out.println(NameAware.nameOf(Person::toString)); | |
} | |
} | |
@FunctionalInterface | |
interface Setter<T, R> extends Serializable { | |
void set(T receiver, R value); | |
} | |
@FunctionalInterface | |
interface Getter<T, R> extends Serializable { | |
R get(T source); | |
} | |
class Person { | |
private String name; | |
private int age; | |
private boolean male; | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public int getAge() { | |
return age; | |
} | |
public void setAge(int age) { | |
this.age = age; | |
} | |
public boolean isMale() { | |
return male; | |
} | |
public void setMale(boolean male) { | |
this.male = male; | |
} | |
} | |
class NameAware { | |
public static <T, R> String nameOf(Getter<T, R> getter) { | |
return getLambda(getter).map(SerializedLambda::getImplMethodName) | |
.map(it -> normalize(it, "get", "is")) | |
.orElseThrow(() -> new RuntimeException("not a getter method")); | |
} | |
public static <T, R> String nameOf(Setter<T, R> setter) { | |
return getLambda(setter).map(SerializedLambda::getImplMethodName) | |
.map(it -> normalize(it, "set")) | |
.orElseThrow(() -> new RuntimeException("not a setter method")); | |
} | |
private static String normalize(String name, String... prefixes) { | |
return Arrays.stream(prefixes).filter(name::startsWith).findAny() | |
.map(prefix -> Character.toLowerCase(name.charAt(prefix.length())) + name.substring(prefix.length() + 1)) | |
.orElse(null); | |
} | |
private static Optional<SerializedLambda> getLambda(Serializable func) { | |
try { | |
Method writeReplace = func.getClass().getDeclaredMethod("writeReplace"); | |
writeReplace.setAccessible(true); | |
SerializedLambda lambda = (SerializedLambda) writeReplace.invoke(func); | |
return Optional.ofNullable(lambda); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
return Optional.empty(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment