Добавление методов в класс с помощью Groovy в Java

Я работаю над модулем Java, который использует Groovy в качестве зависимости от времени компиляции, и я хотел бы добавить метод в свой класс Java Person (например, Groovy JDK) без написания кода Groovy.

В Groovy я бы добился этого вот так

Person.meta.doSomething = { String param -> println "do something: ${param}" }

Как я могу это сделать, используя Groovy API на Java?

ИЗМЕНИТЬ 1:

До сих пор я реализовал следующее, и я почти готов. Я создаю экземпляр класса Expando для Person и регистрирую MethodClosure, который делегирует вызов метода методу в классе PersonDefaultMethods.

ExpandoMetaClass expando = new ExpandoMetaClass (Person.class, true, false);
expando.registerInstanceMethod ("format", new MethodClosure (new PersonDefaultMethods(), "format"));
expando.initialize ();

PersonDefaultMethods содержит реализацию методов, которые я объявил в классе Expando.

public class PersonDefaultMethods {
   public String format(String format) {
      return this.toString(); // this one gets called
   }

   public String format(Person self, String format) { // but I want this method to be called
      return self.getFirstname() + " " + self.getLastname();
    }
}

Когда я знаю, что выполнить сценарий Groovy в этом контексте, я могу вызвать метод format в экземпляре Person, но не могу получить доступ к delegate, как обычно, используя закрытие.

ИЗМЕНИТЬ 2:

Подход с использованием подкласса закрытия или анонимного класса закрытия не работает в моей реализации.

ExpandoMetaClass expando = new ExpandoMetaClass(Person.class, true, false);
expando.registerInstanceMethod("format", new Closure(this) {

     @Override
     public Object call(Object arguments) {
        return super.call(arguments);
     }

     @Override
     public Class[] getParameterTypes () {
        return new Class[] { String.class};
     }
  });
expando.initialize ();

Это делает свою работу. Спасибо.


person saw303    schedule 02.09.2015    source источник
comment
Даже если вы сможете заставить это работать, разве ваш код не превратится в беспорядок поиска и вызовов реестра? Java не подходит для такого рода расширений Instance. Следовательно, Groovy   -  person tim_yates    schedule 02.09.2015
comment
Абсолютно согласен с тобой. Единственная причина, по которой я пытаюсь использовать этот подход, заключается в том, что моя компания использует Eclipse (без поддержки Groovy), и если я начну помещать классы Groovy в их рабочее пространство, проект больше не будет строиться ... Я знаю, что это плохой ситуация, но я не могу ее изменить (пока).   -  person saw303    schedule 02.09.2015
comment
re: невозможно получить доступ к делегату. В MethodClosure делегат / владелец используется для вызова метода, здесь PersonDefaultMethods, поэтому так работать не будет. Вам понадобится подкласс Closure.   -  person blackdrag    schedule 04.09.2015


Ответы (1)


Вы можете получить текущий мета-класс через GroovySystem.getMetaClassRegistry().getMetaClass(Person.class); лучше. Но чтобы смоделировать описанное выше, вам нужно сделать несколько вещей вручную, которые Groovy делает за вас в фоновом режиме.

  • Прежде всего, вам понадобится ExpandoMetaClass (сокращенно EMC). Если указанный выше метакласс не является EMC, вам нужно будет создать его и зарегистрировать в реестре: ExpandoMetaClass emc = new ExpandoMetaClass(Person.class).
  • Затем вам нужно будет вызвать registerInstanceMethod либо с помощью String и Closure, либо с помощью MetaMethod. Вышеупомянутый вариант является версией Closure и будет вызывать другую в фоновом режиме.
  • Чтобы следовать соглашениям Groovy, вам необходимо создать подкласс Closure (возможно, анонимный) с методом doCall подписи, которой вы хотите, чтобы ваш метод был. Строка для registerInstanceMethod будет именем метода
  • Конечно, вы также можете использовать один из существующих подклассов MetaMethod (или свой собственный), чтобы добраться туда.
person blackdrag    schedule 02.09.2015
comment
Спасибо за ваше объяснение. Я применил его, но теперь столкнулся с исключением (см. Обновленный вопрос) - person saw303; 04.09.2015