Могу ли я передать сложную структуру типов в Java-дженериках?

В настоящее время я пытаюсь реализовать API для концептуальной модели с использованием интерфейсов Java и дженериков. Модель (Transmodel V5.0) подробно описывается как модель отношения сущности, но она не указывает некоторые используемые базовые типы. Например, типы идентификаторов для разных объектов или типы, используемые для установления порядка в последовательностях, не определены.

Поскольку я хочу, чтобы API как можно более общий, я начал использовать generics для настройки этих деталей. Я не хочу делать какие-либо предположения о типах, в том числе не предполагая, что что-либо согласовано. Каждый объект может иметь различный тип идентификатора, каждая последовательность может иметь другой тип, используемый для целей заказа.

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

Например, у меня есть:

/**
 * @param <ID> The type for the identifier of this entity.
 * @param <ID_JP> The type identifying journey patterns.
 * @param <OP_JP> The ordering used for points in journey patterns.
 * @param <JP> The type of journey pattern referenced by this entity.
 */
public interface VehicleJourney<
        ID,
        ID_JP, OP_JP extends Comparable<OP_JP>, JP extends JourneyPattern<ID_JP, OP_JP>
    > extends IdentifiableObject<ID>
{
    JP getJourneyPattern();
}

Я все еще могу прочитать это и понять, но он становится более чем многословным. И тогда такие объекты, как VehicleJourney, могут ссылаться на другие объекты, что приводит к взрыву списка параметров типа. Это почти самый маленький нетривиальный пример, о котором я могу думать.

Есть ли способ создать единый объект Java, который моделирует всю конфигурацию системы типов? Я думаю о том, что будет иметь все типы идентификаторов и типы упорядочения, и затем может быть передан как один, превратив пример выше в нечто вроде этого:

public interface VehicleJourney<CONF, JP extends JourneyPattern<CONF>> 
       extends IdentifiableObject<???>
{
    JP getJourneyPattern();
}

В месте с вопросительными знаками тип идентификатора VehicleJourney должен каким-то образом быть извлечен из CONF. Если это будет осуществимо, то сложность должна оставаться на управляемом уровне.

Ответ 1

Не будет красивым.

Вы можете использовать unanchored типы и упростить, имея тип, который группирует типы id и compator:

public interface Meta<ID, COMP extends Comparable<COMP>> {

}

public interface IdentifiableObject<M extends Meta<?, ?>> {

}

public interface JourneyPattern<M extends Meta<?, ?>>
        extends IdentifiableObject<M> {

}

public interface VehicleJourney<M extends Meta<?, ?>, JP extends JourneyPattern<?>>
        extends IdentifiableObject<M> {

}

Вам действительно не нужно указывать имена для привязки вложенных типов типов. Когда у вас есть конкретный класс (или даже суб-интерфейсы), все типы будут привязаны в любом случае. Например:

public class VehicleJourneyImplMeta implements Meta<String, String> {

}

public class VehicleJourneyImpl extends IdentifiableObjectBase<VehicleJourneyImplMeta> 
        implements VehicleJourney<
                VehicleJourneyImplMeta, 
                JourneyPattern<Meta<Integer, String>>> {

}

Вам нужно будет делегировать доступ к типам в Meta, используя промежуточные классы, наиболее вероятно анонимные:

VehicleJourney<Meta<String, String>, ?> v = something();
Meta<String, String> m = v.getObjectMeta();
String idOfV = m.getId();

С помощью различных параметров типа на уровне метода вы, вероятно, можете сделать эту работу.

Мне кажется, что вы (и я, и большинство людей) действительно хотите что-то вроде этого:

public interface VehicleJourney<M extends Meta<?, ?>, JP extends JourneyPattern<?>>
        extends IdentifiableObject<M> {

        public JP.M.ID getIdOfReferencedX();
}

К сожалению, Java не поддерживает типизацию JP.M.ID как возвращаемого типа. Возможно, кто-то поднимет JSR для этого. Байт-код содержит имена параметров типового типа, если я правильно помню.