2014-12-22 11 views
10

moje pytanie jest mocno związane z Explicit use of LambdaMetafactory w tym wątku, niektóre bardzo dobre przykłady są przewidziane do korzystania z LambdaMetafactory, aby uzyskać dostęp do statycznej metody klasy; Zastanawiam się jednak, jaki jest równoważny kod dostępu do niestatycznego pola istniejącej instancji komponentu bean. Bardzo trudno jest znaleźć przykład, a każda próba, którą wykonałem, zakończyła się niedziałającym kodem.Metody Java bean dostępu z LambdaMetafactory

Jest to kod fasola:

class SimpleBean { 
    private Object obj= "myCustomObject"; 
    private static Object STATIC_OBJECT = "myCustomStaticObject"; 
    public Object getObj() { 
     return obj; 
    } 
    public void setObj(final Object obj) { 
     this.obj = obj; 
    } 
    public static Object getStaticObj() { 
     return STATIC_OBJECT; 
    } 
    public static void setStaticObj(final Object obj) { 
     STATIC_OBJECT = obj; 
    } 
} 

Oto test jednostka robocza, które z powodzeniem uzyskać dostęp do metody statycznej "getStaticObj()":

@Test 
public void accessStaticMethod() throws Throwable 
{ 
    MethodHandles.Lookup caller = MethodHandles.lookup(); 
    Method reflected = SimpleBean.class.getDeclaredMethod("getStaticObj"); 
    MethodHandle methodHandle = caller.unreflect(reflected); 
    CallSite site = LambdaMetafactory.metafactory(caller, 
      "get", 
      MethodType.methodType(Supplier.class), 
      MethodType.methodType(Object.class), 
      methodHandle, 
      MethodType.methodType(Object.class)); 
    MethodHandle factory = site.getTarget(); 
    Supplier r = (Supplier) factory.invoke(); 
    assertEquals("myCustomStaticObject", r.get()); 
} 

Teraz tutaj moje upadających próbuje uzyskać dostęp do non statyczna metoda "getObj()":

@Test 
public void accessNonStaticMethodTestOne() throws Throwable 
{ 
    SimpleBean simpleBeanInstance = new SimpleBean(); 

    MethodHandles.Lookup caller = MethodHandles.lookup(); 
    MethodHandle methodHandle = caller.bind(simpleBeanInstance, "getObj", MethodType.methodType(Object.class)); 
    assertEquals("myCustomObject", methodHandle.invoke()); 

    // This test fails here with exception: 
    // java.lang.IllegalArgumentException: not a direct method handle 
    CallSite site = LambdaMetafactory.metafactory(caller, 
      "get", 
      MethodType.methodType(Supplier.class), 
      MethodType.methodType(Object.class), 
      methodHandle, 
      MethodType.methodType(Object.class)); 

    MethodHandle factory = site.getTarget(); 
    Supplier r = (Supplier) factory.invoke(); 
    assertEquals("myCustomObject", r.get()); 

} 

@Test 
public void accessNonStaticMethodTwo() throws Throwable 
{ 

    SimpleBean simpleBeanInstance = new SimpleBean(); 

    MethodHandles.Lookup caller = MethodHandles.lookup(); 

    Method reflected = SimpleBean.class.getDeclaredMethod("getObj"); 
    MethodHandle methodHandle = caller.unreflect(reflected); 

    // This test fails here with exception: 
    // java.lang.invoke.LambdaConversionException: Incorrect number of parameters 
    CallSite site = LambdaMetafactory.metafactory(caller, 
      "get", 
      MethodType.methodType(Supplier.class), 
      MethodType.methodType(Object.class), 
      methodHandle, 
      MethodType.methodType(Object.class)); 

    MethodHandle factory = site.getTarget(); 
    factory = factory.bindTo(simpleBeanInstance); 
    Supplier r = (Supplier) factory.invoke(); 
    assertEquals("myCustomObject", r.get()); 

} 


@Test 
public void accessNonStaticMethodThree() throws Throwable 
{ 

    SimpleBean simpleBeanInstance = new SimpleBean(); 

    MethodHandles.Lookup caller = MethodHandles.lookup(); 

    Method reflected = SimpleBean.class.getDeclaredMethod("getObj"); 
    MethodHandle methodHandle = caller.unreflect(reflected); 

    CallSite site = LambdaMetafactory.metafactory(caller, 
      "get", 
      MethodType.methodType(Supplier.class), 
      MethodType.methodType(Object.class, SimpleBean.class), 
      methodHandle, 
      MethodType.methodType(Object.class, SimpleBean.class)); 

    MethodHandle factory = site.getTarget(); 

    //This test fails here with exception: 
    // java.lang.IllegalArgumentException: no leading reference parameter: [email protected] 
    factory = factory.bindTo(simpleBeanInstance); 
    Supplier r = (Supplier) factory.invoke(); 
    assertEquals("myCustomObject", r.get()); 

} 

Każda próba ma inny negatywny wynik, I r eally nadzieję, że ktoś jest abe, aby pomóc mi mieć co najmniej jeden test działa dobrze.

+1

Zobaczmy twoje próby. Wyjaśnij, dlaczego je wypróbowałeś i dlaczego nie działały. –

+0

Jakie jest twoje pytanie? – Bonifacio2

+0

Dodałem przykładowy kod. Wyjątki zgłaszane w czasie wykonywania są wyjaśnione w samym kodzie testowym. –

Odpowiedz

17

Jeśli chcesz powiązać wartości do Lamba, trzeba uwzględnić te parametry do podpisu invokedtype:

SimpleBean simpleBeanInstance = new SimpleBean(); 

MethodHandles.Lookup caller = MethodHandles.lookup(); 
MethodType getter=MethodType.methodType(Object.class); 
MethodHandle target=caller.findVirtual(SimpleBean.class, "getObj", getter); 
CallSite site = LambdaMetafactory.metafactory(caller, 
    "get", // include types of the values to bind: 
    MethodType.methodType(Supplier.class, SimpleBean.class), 
    getter, target, getter); 

MethodHandle factory = site.getTarget(); 
factory = factory.bindTo(simpleBeanInstance); 
Supplier r = (Supplier) factory.invoke(); 
assertEquals("myCustomObject", r.get()); 

Zamiast wiązania wartości można użyć Function która przyjmuje fasoli jako argument:

SimpleBean simpleBeanInstance = new SimpleBean(); 

MethodHandles.Lookup caller = MethodHandles.lookup(); 
MethodType getter=MethodType.methodType(Object.class); 
MethodHandle target=caller.findVirtual(SimpleBean.class, "getObj", getter); 
MethodType func=target.type(); 
CallSite site = LambdaMetafactory.metafactory(caller, 
    "apply", 
    MethodType.methodType(Function.class), 
    func.generic(), target, func); 

MethodHandle factory = site.getTarget(); 
Function r = (Function)factory.invoke(); 
assertEquals("myCustomObject", r.apply(simpleBeanInstance)); 
+0

Hi Holger, twoja praca dobrze dla wszystkich pobierających, działa nawet z prymitywnymi parametrami. Jednak jestem w stanie zastosować go do metod setera. Na podstawie tego przykładu uważam, że zamiast funkcji należy użyć interfejsu BiConsumer, tutaj moja próba: 'Setter methodType = MethodType.methodType (Void.TYPE, Object.class); MethodHandle target = caller.findVirtual (SimpleBean.class, "setObj", seter); MethodType func = target.type(); CallSite site = LambdaMetafactory.metafactory (wywołujący, "Akceptuję", MethodType.methodType (BiConsumer.class) func.generic(), cel, \t func); ' fabryka i rzuca wyjątek –

+4

Chociaż' func.generic () 'jest przydatny w wielu przypadkach użycia, nie działa dobrze dla metod' void' z metafactory lambda. Musimy więc zamienić 'func.generic()' na 'func.changeParameterType (0, Object.class)' ... – Holger

Powiązane problemy