Я пытаюсь написать общую служебную функцию scala для работы с классами Java, сгенерированными Apache Thrift. Все сгенерированные Thrift Java-классы расширяют интерфейс TBase следующей подписью:

public interface TBase<T extends TBase<?,?>, F extends TFieldIdEnum>

Это, безусловно, всегда было проблематично при создании общих функций служебных функций, и в мире Java я обычно решал эту проблему, просто используя @SuppressWarnings("rawtypes"), зная, что я справлялся с этим правильно, и эффективно игнорируя компилятор, говорящий мне, что он может ' проверить соответствие типов.

В мире scala я, кажется, не могу позволить себе роскошь или игнорирование этих типов, и я столкнулся с ситуацией, когда я не могу понять, как удовлетворить требования универсального типа.

Итак, я создал свою собственную функцию, которая преобразует данный объект, не относящийся к Thrift, в экземпляр запрошенного класса Thrift с сигнатурой, похожей на:

def myFunc[T <: TBase[T, E], E<: TFieldIdEnum](obj: Any, clazz: Class[T]): T = {

Поэтому моя проблема заключается в том, что для вызова этой функции мне нужно сделать что-то вроде:

myFunc[MyThriftClass,MyThriftClass._Fields]( obj, classOf[MyThriftClass] )

Без явно заданного параметра второго типа компиляция завершается неудачно с:

error: inferred type arguments [MyThriftClass,Nothing] do not conform to method myFunc's type parameter bounds [T <: org.apache.thrift.TBase[T,E],E <: org.apache.thrift.TFieldIdEnum]
    myFunc( null, classOf[MyThriftClass])
    ^
error: type mismatch;
found   : Class[MyThriftClass](classOf[MyThriftClass])
required: Class[T]
   myFunc( null, classOf[MyThriftClass])

Когда я передаю оба параметра типа, все работает, хотя я предпочел бы только передать класс.

Но то, что я не могу понять, как заставить это работать, если я не знаю типы во время компиляции.

Например, экономичные метаданные определяются с помощью FieldValueMetaData объектов, а при наличии подструктуры предоставляется объект метаданных StructMetaData, который содержит поле

public final Class<? extends TBase> structClass;

Учитывая, что в этом классе отсутствуют параметры типа, я не знаю, как вызывать с ним мой метод, удовлетворяя ограничениям универсального типа. В случае рекурсии мне удалось обойти это, приведя класс substruct к экземпляру Class[T], что неверно, потому что это родительский тип, а не подтип, но из-за стирания типа это делает компилятор счастливым и работает во время выполнения. Но если у меня еще нет универсального типа для приведения, я не знаю, как справиться с этим, за исключением, может быть, действительно хакерского подхода, когда я приводил его к какой-то фальшивой оболочке класса TBase, просто чтобы сделать компилятор счастливым.

Есть ли правильный способ настроить это, чтобы компилятор был доволен реальными типами? В качестве альтернативы есть способ обойти это так же, как в чистой Java с @SuppressWarnings("rawtypes"). В противном случае, если нет, то, возможно, мне просто придется перенести эту логику на Java и вызвать ее из Scala, чтобы сделать все счастливым. Прежде чем сделать это, я бы хотел узнать, чего мне не хватает, или узнать, почему то, что я хочу, невозможно.

0
user1084563