Определите поле с общим типом, используя ByteBuddy

Я только начал играть с ByteBuddy и работаю над парой примеров, чтобы освоиться.

В этом упражнении я пытаюсь заменить некоторый код, использующий ASM, на ByteBuddy.

До сих пор я был успешным, когда дело доходит до необобщенных типов. Например, я могу легко определить поле, например, вот так

builder.defineField("names", List.class, Visibility.PRIVATE)

если все, что я хочу сделать, это создать поле необработанного типа List.

Однако когда дело доходит до введения дженериков, я застрял.

Очевидно, то, как я определил поле (используя Class), означает, что общие типы потеряны. Читая документацию (особенно часть Working with generic types), я не могу понять, как создать Поле списка, если оно имеет известный универсальный тип, например, если это другой POJO. Скажем, у меня есть следующий POJO:

public class Dummy {
   private String name;

   //getters, setters
}

и я хочу создать поле List<Dummy>, как мне выполнить такую ​​задачу?

Спасибо!


person geoand    schedule 24.08.2017    source источник
comment
Просто для протокола: вы знаете о стирании типов и о том, что сгенерированный класс не знает, что поле является списком конкретно Dummy?   -  person GhostCat    schedule 24.08.2017
comment
@GhostCat Конечно! Однако есть некоторые «магические» случаи, когда я могу узнать стертый тип (например, см. Джексона)   -  person geoand    schedule 24.08.2017
comment
Конечно, сгенерированный класс знает о своей универсальной сигнатуре поля. Стирание означает, что экземпляр универсального класса не знает о своем универсальном типе. Но он знает родовые типы своих членов.   -  person Rafael Winterhalter    schedule 25.08.2017


Ответы (1)


Вместо предоставления Class<List> методу defineField вы можете указать Type. ByteBuddy имеет вспомогательный класс для создания универсальных типов, поэтому вам не нужно создавать реализацию самостоятельно. Я поместил его в отдельную строку, чтобы сделать его более заметным.

    // Create List<Dummy> as Type
    Generic generic = TypeDescription.Generic.Builder
            .parameterizedType(List.class, Dummy.class).build();

    Class<? extends Example> loaded = new ByteBuddy().subclass(Example.class)
            .defineField("names", generic, Visibility.PRIVATE).make()
            .load(ByteBuddyEnhancer.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION).getLoaded();

Одним из способов проверки того, что поле действительно установлено и содержит общие параметры, является этот тестовый пример.

    Field field = loaded.getDeclaredField("names");
    Type fieldType = field.getGenericType();
    Assert.assertTrue(fieldType instanceof ParameterizedType);
    ParameterizedType genericFieldType = (ParameterizedType)fieldType;
    Assert.assertEquals(Dummy.class, genericFieldType.getActualTypeArguments()[0]);
    System.out.println(genericFieldType.getRawType());
    System.out.println(genericFieldType.getActualTypeArguments()[0]);
person k5_    schedule 24.08.2017