Реализация метода ByteBuddy, который создает новый объект - PullRequest
0 голосов
/ 10 февраля 2020

Я использую Byte Buddy 1.9.0 в качестве генератора кода для языка программирования на основе Xtext, и я изо всех сил пытаюсь создать байт-код для метода, который создает экземпляр «анонимного» класса. Для всех намерений и целей я пытаюсь, чтобы Byte Buddy создал метод, эквивалентный этому:

package fxxx.test;
class DummyUser
{
  DummyOperator dummy()
  {
    return new DummyUser$1();
  }
}

Мой компилятор уже создал вложенный "анонимный" класс DummyUser$1, но, для жизни я не могу придумать правильную последовательность инструкций Byte Buddy, чтобы создать новый объект этого класса и затем вернуть этот объект. После некоторого поиска я наткнулся на MethodCall.construct(MethodDescription), но мой текущий код выдает только следующее исключение:

java.lang.IllegalStateException: Cannot return void from public fxxx.test.DummyOperator fxxx.test.DummyUser_.dummy()
    at net.bytebuddy.implementation.MethodCall$TerminationHandler$1.resolve(MethodCall.java:2189)
    at net.bytebuddy.implementation.MethodCall.toStackManipulation(MethodCall.java:2405)
    at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:2434)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:698)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:683)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:590)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:5114)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1915)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:197)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3376)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3565)
...

Эта ошибка, кажется, довольно понятно говорит мне, что, поскольку конструктор для класса имеет <init>()V сигнатура и технически возвращает void это эквивалентно возвращению void значения из метода, который должен действительно возвращать некоторый подкласс DummyOperator. Я попытался объединить MethodCall.construct с StackManipulation, который дублирует вершину стека, но, поскольку TypeCreation через байт-код new уже запекан в MethodCall.construct, я не имею доступа к недавно созданный экземпляр необработанного объекта. Проект еще не открыт, но я могу предоставить этот фрагмент (используя синтаксис Xtend), чтобы проиллюстрировать, что делает мой код:

    val Builder<?> anonymousClass = ... // the anonymous class that has already been created
    val TypeDescription declaringType = describe(anonymousClass) // basically .make.typeDescription
    val MethodDescription constructor = method(declaringType, new TypeDescription.ForLoadedType(void), "<init>", #[]) // new Latent declaringType/returnType
    val MethodCall construct = MethodCall.construct(constructor)
    // ^^^ this value gets return as the new method's Implementation

Чего мне не хватает, чтобы метод правильно возвращал вновь созданный экземпляр?

1 Ответ

1 голос
/ 10 февраля 2020

Итак, похоже, что я все-таки не пропустил ни одного шага или обязательно сделал что-то не так с самой реализацией объекта. Когда я запустил это в отладчике, я заметил, что недопустимая манипуляция со стеком была вызвана несовпадением типов, что указывало на то, что метод возвращаемого типа на самом деле не был совместим с типом анонимного класса (ошибка с моей стороны; тип языка система немного более сложна, чем, скажем, обычная Java, и эти два типа были несовместимы в некотором смысле). Я думаю, что извлеченный урок заключается в двойной проверке совместимости типов при обнаружении исключений, подобных приведенным выше.

...