2017-05-15 18 views
6

Bu, Java8 retrieving lambda setter from class numaralı makalenin bir bölümüdür. Bunun nedeni bir tür uyumsuzluğu nedeniyle, derleme değilGenel lambda ifadesinde güven tipinin güvence altına alınması

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, String fieldName, Class<R> fieldType) { 

    MethodHandles.Lookup caller = null; 
    MethodHandle target = null; 
    MethodType func = null; 

    try { 
     caller = MethodHandles.lookup(); 
     MethodType getter = MethodType.methodType(fieldType); 
     target = caller.findVirtual(clazz, computeGetterName(fieldName), getter); 
     func = target.type(); 
    } catch (NoSuchMethodException e) { 
     error("Could not locate a properly named getter \"" + computeGetterName(fieldName) + "\"!"); 
    } catch (IllegalAccessException e) { 
     error("Could not access \"" + computeGetterName(fieldName) + "\"!"); 
    } 

    CallSite site = null; 
    try { 
     site = LambdaMetafactory.metafactory(
       caller, 
       "get", 
       MethodType.methodType(IGetter.class), 
       func.generic(), 
       target, 
       func 
     ); 
    } catch (LambdaConversionException e) { 
     error("Could not convert the getter \"" + computeGetterName(fieldName) + "\" into a lambda expression!"); 
    } 

    MethodHandle factory = site.getTarget(); 

    IGetter<T, R> r = null; 
    try { 
     r = (IGetter<T, R>) factory.invoke(); 
    } catch (Throwable throwable) { 
     error("Casting the factory of \"" + computeGetterName(fieldName) + "\" failed!"); 
    } 

    return r; 
} 

:

ben belirli bir alanda

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Field field) { 

    Class<R> fieldType = null; 
    try { 
     fieldType = (Class<R>) field.getType(); 
    } catch(ClassCastException e) { 
     error("Attempted to create a mistyped getter for the field " + field + "!"); 
    } 

    return getGetter(clazz, field.getName(), fieldType); 
} 

Bu altta yatan bir yöntemdir için bir alıcı yöntemini almaya çalışıyorum

IGetter<TestEntity, Long> getter = accessorFactory.getGetter(TestEntity.class, "name", String.class); 

Ancak bu derleme yapar:

Field field = TestEntity.class.getDeclaredField("name"); 
IGetter<TestEntity, Long> getter = accessorFactory.getGetter(TestEntity.class, field); 

Ve benim için sürpriz, bu yukarıda ele geçirildi toplama maddesinin kullanarak çalışır:

TestEntity testEntity = new TestEntity(1L, "Test"); 
System.out.println(getter.get(testEntity)); 

Ancak yapmam kez bu: Aşağıdaki özel durum almak

Long value = getter.get(testEntity); 

:

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long 
    at de.cyclonit.exercise.Main.main(Main.java:26) 

Bunu daha önce yakalamanın bir yolu var mı?

TestEntity sınıfı:

public class TestEntity { 

    private Long id; 

    private String name; 


    public TestEntity(Long id, String name) { 
    this.id = id; 
     this.name = name; 
    } 


    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 
} 

cevap

7

Sorun yöntem

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Field field) { 
    Class<R> fieldType = null; 
    try { 
     fieldType = (Class<R>) field.getType(); 
    } catch(ClassCastException e) { 
     error("Attempted to create a mistyped getter for the field " + field + "!"); 
    } 
    return getGetter(clazz, field.getName(), fieldType); 
} 

aslında bir kontrol yaptıktan olmamasıdır. Hiçbir etkisi olmayan Class türüne temel olarak Class10 örneğini döküyorsunuz. Class<?> ile Class<R> arasındaki jenerik tipteki değişiklik, tam bir derleme zamanıdır; bu nedenle, en azından, tüm uyarıların etkinleştirilmesi durumunda, bu noktada "işaretlenmemiş" bir uyarı almanız gerekir. o biraz anlamsız bir Field kabul yöntemi yapar Tabii

public <T, R> IGetter<T, R> getGetter(Class<T> clazz, Class<R> fieldType, Field field) { 
    if(fieldType != field.getType()) { 
     error("Attempted to create a mistyped getter for the field " + field + "!"); 
    } 
    return getGetter(clazz, field.getName(), fieldType); 
} 

:

zamanında bir gerçek çek yapmanın tek yolu, arayanın beklenen türü elde etmektir. Gerçek getGetter, alıcının dönüş türüyle tam bir eşleşme gerektiren bir arama gerçekleştirecek ve alanın türü ile alıcının dönüş türünün eşleşmesi gerekmeden hiçbir şey elde edemeyeceksiniz. Aslında iç detaylara gereksiz bir bağımlılık yaratır.

Neden alanların yerine alıcılara açıklama ekleyelim…

İlgili konular