Преобразовать VarHandle в java.lang.reflect.Поле

#java #reflection #java-9

#java #отражение #java-9

Вопрос:

Есть ли какой-либо способ преобразовать из a VarHandle в a java.lang.reflect.Field ? С помощью (getter / setter) MethodHandle можно использовать MethodHandles.reflectAs(Field.class, handle) для перехода от MethodHandle к Field или lookup.unreflect{Getter|Setter}(field) для перехода от Field к MethodHandle . Аналогично, можно использовать lookup.unreflectVarHandle(field) для перехода от Field к VarHandle , но, похоже, нет никакого эквивалентного способа перехода от VarHandle к Field .

Ответ №1:

Похоже, такая функция действительно отсутствует.

Но, начиная с JDK 12, вы можете эмулировать его через constant API:

 Optional<Field> o = varHandle.describeConstable().map(d -> {
    String mName = d.bootstrapMethod().methodName();
    if(mName.equals("staticFieldVarHandle") || mName.equals("fieldVarHandle")) try {
        return ((Class<?>)((ClassDesc)d.bootstrapArgsList().get(0))
            .resolveConstantDesc(MethodHandles.lookup()))
            .getDeclaredField(d.constantName());
    } catch (ReflectiveOperationException ex) {}
    return null;
});
  

Это обеспечивает Field , когда VarHandle описывается доступное поле.

Комментарии:

1. Хороший трюк, но немного не хватает, поскольку поле должно быть доступным, тогда MethodHandles.reflectAs как работает, даже если поле недоступно. Интересно, что способ, которым Java 12 реализует этот describeConstable метод, заключается не в добавлении MethodName в VarHandle anywhere , а в добавлении VarHandles.getFieldFromReceiverAndOffset и VarHandles.getStaticFieldFromBaseAndOffset , которые возвращают Field и могут быть тривиально использованы для реализации чего-то подобного VarHandle.reflect .

2. Ну, обычно, в первую очередь нелегко создать a VarHandle для недоступного поля. Не то, чтобы ограничение доступности применялось только к классу owner, затем поле просматривается через обычный getDeclaredField , который может видеть недоступные поля. В принципе, вы могли бы даже извлечь имя класса и выполнить поиск самостоятельно. Но да, это все равно не будет таким же, как a reflectAs , который работает независимо от контекста вызывающего.

3. Я думаю о случае, когда VarHandle создается из вызывающего объекта, который может видеть поле, а затем передается служебному классу, который не может (например, что-то вроде AtomicReferenceFieldUpdater). Если служебному классу требуется дескриптор отраженного поля (для утверждений типа или тому подобного), простого способа его получить нет. Альтернативой является вместо этого передача MethodHandle . Поиск и имя поля, и пусть служебный класс выполняет поиск поля (отражается на дескрипторе getter) и самого varhandle .

4. Я думаю, мы согласны с тем, что это недостающая функция…