0

런타임시 biPredicate로 사용할 함수 이름을 수신합니다. 이 biPredicate를 전달하고 평가하기 위해 기본적으로 필터를 사용하여 결과를 얻고 싶습니다. 다음은 biPredicates를 정의하는 유틸리티입니다. 나는 MethodHandle과 Lambda 함수를 사용해 보았습니다. 내가다른 함수에 술어로 함수를 전달하는 방법, RunTime에 술어 함수의 이름을받을 때?

new FilterUtility().execute("genericFilter"); 

을 사용하면 내가 다음에 실행의 구현을 변경할 때 나는 예외를 얻을 해달라고, java.lang.AbstractMethodError

public class FilterUtility { 

public void execute(String filterName) throws Throwable { 
    ActualBean beanObject = ActualBean.builder().param1("true").param2("false").build(); 

    MethodType methodType = MethodType.methodType(boolean.class, Object.class, Object.class); 
    MethodHandles.Lookup lookup = MethodHandles.lookup(); 
    MethodHandle handle = lookup.findStatic(FilterUtility.class, filterName, methodType); 
    BiPredicate<Object, Object> f = (BiPredicate<Object, Object>) LambdaMetafactory.metafactory(lookup, 
      "test", 
      MethodType.methodType(BiPredicate.class), 
      methodType.generic(), 
      handle, 
      methodType) 
      .getTarget() 
      .invokeExact(); 

    resolve(beanObject, new HashMap<>(), f); 
} 

public static <SourceObject, TemplateObject> Map<String, String> resolve(SourceObject src, 
     TemplateObject template, 
     BiPredicate<SourceObject, TemplateObject> p) { 
    if (p.test(src, template)) 
     return new HashMap<>(); 

    return null; 
} 

public static <SourceObject, TemplateObject> boolean genericFilter(SourceObject x, TemplateObject y) { 
    ObjectMapper ob = new ObjectMapper(); 
    Map<String, Object> source = ob.convertValue(x, Map.class); 
    Map<String, Object> template = ob.convertValue(y, Map.class); 

    for (Map.Entry<String, Object> entry : template.entrySet()) { 
     if (!source.get(entry.getKey()).equals(entry.getValue())) 
      return false; 
    } 
    return true; 
} 
} 

를 얻을.

public void execute(String filterName) throws Throwable { 
    ActualBean beanObject = ActualBean.builder().param1("true").param2("false").build(); 
    resolve(beanObject, new HashMap<>(), FilterUtility::genericFilter); } 

이 제가 이름을 가진 기능을 찾아서 biPredicate로 보내려고하고있는 방법에 문제가 있다고 생각합니다.

+0

제가 은'MethodHandle 핸들 lookup.findStatic (FilterUtility.class, FILTERNAME, methodType는) = 중지 디버거를 사용 , String>()); ' ** 그것은 java.lang.UnsupportedOperationException을 제공합니다. 메시지 : MethodHandle.invoke는 반사적으로 호출 할 수 없습니다 ** –

+0

12 행의'.generic()을 제거하십시오. –

답변

2

모든 매개 변수 유형을 대체하는 methodType.generic() 메소드를 호출하고 프리미티브 유형을 포함하여 반환 유형을 java.lang.Object으로 호출합니다. 따라서 대상 메서드의 서명 (Object,Object)->boolean(Object,Object)->Object으로 변환하면서 대상 메서드를 호출하고 결과를 상자에 넣는 Object test(Object,Object) 메서드로 효과적으로 클래스를 만듭니다.

이러한 유형 불일치는 람다 메타 속성에 의해 확인되지 않습니다. 따라서 BiPredicate의 메소드 boolean test(Object,Object)을 생성 된 클래스에서 호출하려고하면 오류가 발생합니다.

올바른 방법은 methodType.erase()이며 모든 참조 유형은 java.lang.Object으로 바뀌지 만 원시 유형은있는 그대로 유지합니다. 이 특정 경우에는 대상 메서드의 형식이 이미 (Object,Object)->boolean이므로 methodType.generic()methodType으로 바꾸면 메서드 형식을 전혀 변형 할 필요가 없습니다. ` 는 그때 `handle.invoke (위하여 새로운의 HashMap <문자열을 실행; I이 방법은 여기에서 처리 만들면

+0

어떻게하면이 문제를 스스로 찾을 수 있습니까? 어쩌면 디버거에서 어떤 트릭을 것입니다 이 정보를 어디서 찾을 수 있습니까? 내가 이미 어디에 있는지 알면 해결할 수있는 더 많은 쟁점을 만나게 될 것이라고 생각한다. –

+0

나는 [LambdaMetafactory'의 클래스 문서] (https://docs.oracle.com/javase/8/docs/api/?java/lang/invoke/LambdaMetafactory.html)는 포괄적 인 것으로 생각합니다. 이것은 주로 전문가 (또는 오히려 생성 된 코드, 컴파일러 또는 전문가가 만든 도구)를 대상으로하기 때문에 모든 속성 검사에 대한 성능을 희생하지 않습니다. – Holger

+0

모든 형식을 완전히 이해하고 (유형 삭제의 의미와 같이), [The Java® Language Specification] (https://docs.oracle.com/javase/specs/jls/se8/html/index)을 숙지하고 있습니다. .html) 및 [The Java® Virtual Machine Specification] (https://docs.oracle.com/javase/specs/jvms/se8/html/index.html)은 불가피합니다. – Holger