Проблемы с доступом к именам параметров методов классов Groovy в Spring AOP 6.1+

Начиная с версии 6.1 «Сохранение имени параметра»

LocalVariableTableParameterNameDiscoverer был удален в версии 6.1».

даже с -parameters в компиляторе Java мы больше не можем делать подобные вещи

@CustomAnnotation(projectIdParameter = "projectId", userIdParameter = "#userEntity.id")
public ProjectEntity getProject(UserEntity userEntity, String projectId)

Потому что в @Before при передаче JoinPoint мы могли делать

joinPoint.getSignature().getParameterNames()

Однако метод getParameterNames() больше недоступен, и если вы приведёте getSignature к MethodSignature, getParameterNames теперь вернет значение null.

Что нам осталось сделать, так это поместить функциональность аспекта в каждый метод, который был аннотирован ранее. Нам нравится использовать АОП для решения этих проблем с типом безопасности, но мы не знаем, как заставить его работать с изменениями в Spring.

Можно ли как-нибудь сохранить наш подход АОП?

ОБНОВЛЕНИЕ: Это все еще проблема, и она очень разочаровывает тем, что то работает, то не работает. И единственный способ это исправить — запустить mvn clean install много раз, пока один из них не заработает.

Вот снимок экрана с последним, что мне нужно было сделать в IntelliJ, чтобы он работал при локальном запуске сервера через службы.

Поможет ли это вам: сохранить имя параметра ?

Dirk Deyne 08.03.2024 21:06

Я только что заметил ваше обновление. Что именно остается проблемой после того, как вы уже приняли мой ответ, который доказывает, что он надежно работает в Maven? Вы говорите о проблеме IntelliJ, которую я для вас создал? В этом случае проблема будет не в том, что описано и отмечено здесь, а в отдельной проблеме, связанной с IDE. Ваше описание и комментарии настолько размыты, что трудно понять, в чем заключается ваша реальная проблема.

kriegaex 12.04.2024 14:18

Тот факт, что def argNames = ((MethodSignature)joinPoint.getSignature()).getParameterName‌​s() одна установка mvn возвращает имена параметров, следующая установка mvn возвращает ноль. Тот же метод, он всегда должен возвращать имена параметров, но в некоторых сборках он не работает, все они имеют -параметры, установленные в конфигурации плагина, поэтому ничего не меняется ни в одной сборке, ни в следующей.

bytor99999 13.04.2024 17:41

С моим примером проекта такого никогда не происходит. Если это произойдет в вашем проекте, задайте новый вопрос и разместите ссылку на полный минимальный репродуктор на GitHub. Никто не сможет отладить ваши недоказанные утверждения. До тех пор, пока не будут получены дополнительные доказательства обратного, я предполагаю, что проблема кроется в компьютере.

kriegaex 13.04.2024 18:02

Я не могу создать минимальный воспроизводитель. Ненавижу, когда меня спрашивают, что это не ваша вина, но не все, что происходит, может быть создано с помощью минимального воспроизводителя, это ПРОСТО происходит с полной кодовой базой. «Проблема стоит перед компьютером». Ф-У, ты ничего обо мне не знаешь. Это совершенно грубо и неуместно.

bytor99999 15.04.2024 15:23

Пожалуйста, не говорите «Я не могу», если правда в том, что «Я не хочу». Или, если вы действительно не можете, воздержитесь от названия себя разработчиком программного обеспечения. Иногда это трудоемкий, но на самом деле довольно тривиальный и механический процесс постепенного удаления элементов из вашего проекта, пока не останется минимальный воспроизводитель. Столь же тривиален процесс анонимизации минимального кода без раскрытия каких-либо секретов компании. Мне не нужно ничего знать о вас, чтобы сделать такое заявление.

kriegaex 15.04.2024 22:57

Ну, очевидно, ваш ответ не работает. И я не единственный в моей команде, у кого возникла эта проблема.

bytor99999 16.04.2024 14:41

Я объясняю снова и снова... «def argNames = ((MethodSignature)joinPoint.getSignature()).getParameterName‌​s() одна установка mvn возвращает имена параметров, следующая установка mvn возвращает ноль». Таким образом, один раз он возвращает список имен аргументов, а затем в другой раз, после выключения сервера и его резервного запуска, он возвращает значение null для того же метода, который он рекомендует. Часть меня теперь думает, что IJ не перестраивает с использованием -параметров, хотя в настройках моего компилятора установлено добавление -параметров при компиляции.

bytor99999 16.04.2024 19:07

А я не могу, что касается строительства небольшого проекта. Зачастую подобные проблемы невозможно воспроизвести на мелкой стороне, хотя в нашем приложении это МНОГО случается со всеми разработчиками серверной части. Не каждую проблему можно показать в небольшом простом проекте.

bytor99999 16.04.2024 19:10

Это становится еще более странным, когда у меня был один метод той же службы, рекомендованный АОП, где вызов getParameters() возвращает значение null, но другие методы в той же службе, рекомендованные АОП, возвращают параметры метода. Но я определенно думаю, что решил проблему. И это проблема IntelliJ. Я изменил настройку компилятора Java, включив при необходимости параметры -parameters, но есть еще одно место, которое необходимо изменить, а именно: Build Tools-Maven-Runner. Делегирование действий сборки/запуска IDE в maven необходимо проверить, и это работает.

bytor99999 16.04.2024 21:55

Если этот флажок снят, и вы измените класс службы так, что IJ придется его снова скомпилировать, он не будет делать этого с параметрами -parameters, даже если у вас есть настройки компилятора Java, настроенные на его добавление. Если он установлен, это означает, что Maven скомпилирует его, и предложенная конфигурация maven, подобная приведенной ниже, означает, что он будет скомпилирован с параметрами -parameters.

bytor99999 16.04.2024 21:56

И мне пришлось решать эту проблему самому. Последняя проблема, которая у меня возникла с IDE. В котором никакая репродукция не показала бы этого.

bytor99999 20.04.2024 03:43

Ваша проблема с IDE была дополнительным вопросом, который вы отредактировали после того, как я уже ответил на исходный вопрос Maven. Здесь это было не по теме, и вам следовало задать новый вопрос, как это принято на Stack Overflow. Расползание прицела здесь считается плохим стилем. Одна проблема, один вопрос. В исходном вопросе даже не упоминаются «IDE», «IntelliJ» и als не помечены соответствующим образом.

kriegaex 20.04.2024 08:41

Как я уже сказал, я даже уже создал задачу IDEA для вашей новой проблемы. Я также знаю обходной путь простого делегирования полномочий от IDEA к Maven и мог бы рассказать вам. Но вы до самого конца упорно твердили, что мое Maven-решение у вас не работает, поэтому я не упомянул обходной путь, потому что у вас создалось впечатление, что ваш собственный POM все еще не исправлен. Вам просто нужно научиться лучше задавать вопросы и быть точным в своих вопросах и комментариях, если их о чем-то спрашивают. Таким образом, вы просто тратите драгоценное время всех, включая свое собственное.

kriegaex 20.04.2024 08:42

Примером простого способа улучшить вопрос или последующий комментарий могло бы быть что-то вроде: «Решение Maven от kriegaex работает нормально, но у меня все еще возникают проблемы при перекомпиляции в IntelliJ IDEA». Но нигде вы не сказали ничего даже подобного. Вместо этого вы сначала приняли, а затем отклонили мой ответ Maven, указав, что решение Maven вам не помогло. Может ли врач помочь вылечить боль в спине у пациента, если больной уверяет, что у него болит палец, а о спине даже не упоминает?

kriegaex 20.04.2024 08:47

Спасибо. Я обязательно сделаю это в следующий раз.

bytor99999 23.04.2024 16:20
0
16
230
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

даже с параметрами -parameters в компиляторе Java мы больше не можем делать такие вещи, как...

Тогда вы делаете что-то не так. Это прекрасно работает как из Maven, так и при автоматическом импорте проекта Maven и запуске из IntelliJ IDEA:

<project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>spring-boot-sample</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <groovy.version>4.0.19</groovy.version>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.gmavenplus</groupId>
        <artifactId>gmavenplus-plugin</artifactId>
        <version>3.0.2</version>
        <executions>
          <execution>
            <goals>
              <goal>execute</goal>
              <goal>addSources</goal>
              <goal>addTestSources</goal>
              <goal>generateStubs</goal>
              <goal>compile</goal>
              <goal>generateTestStubs</goal>
              <goal>compileTests</goal>
              <goal>removeStubs</goal>
              <goal>removeTestStubs</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <parameters>true</parameters>
          <verbose>true</verbose>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.12.1</version>
        <configuration>
          <compilerArgs>
            <arg>-parameters</arg>
          </compilerArgs>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <phase>verify</phase>
            <goals>
              <goal>java</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <mainClass>com.example.Application</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>3.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
      <version>3.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.groovy</groupId>
      <artifactId>groovy</artifactId>
      <version>${groovy.version}</version>
    </dependency>
  </dependencies>

</project>
package com.example;

public @interface CustomAnnotation {
  String projectIdParameter();
  String userIdParameter();
}
package com.example;

import org.springframework.stereotype.Service;

@Service
public class SampleService {
  @CustomAnnotation(projectIdParameter = "projectId", userIdParameter = "#userEntity.id")
  public void doSomething(int foo, String bar, Object zot) {
    System.out.println("Doing something in service method");
  }
}
package com.example

import org.springframework.stereotype.Service

@Service
class GroovyService {
  @CustomAnnotation(projectIdParameter = "projectId", userIdParameter = "#userEntity.id")
  void doSomething(int foo, String bar, Object zot) {
    System.out.println("Doing something in Groovy service method")
  }
}
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {

  public static void main(String[] args) {
    try (ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args)) {
      applicationContext.getBean(SampleService.class).doSomething(11, "dummy", new Integer(42));
      applicationContext.getBean(GroovyService.class).doSomething(11, "dummy", new Integer(42));
    }
  }
}
package com.example;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class SampleAspect {
  @Before("@annotation(CustomAnnotation)")
  public void beforeServiceMethodExecution(JoinPoint joinPoint) {
    System.out.println(joinPoint);
    System.out.println(
      Arrays.toString(
        ((MethodSignature) joinPoint.getSignature()).getParameterNames()
      )
    );
  }
}

Журнал консоли:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ / _` | \ \ \ \
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.2.3)

2024-03-09T14:53:30.327+01:00  INFO 14188 --- [           main] com.example.Application                  : Starting Application using Java 21 with PID 14188 (C:\Users\Alexander\Documents\java-src\SO_AJ_Spring61ParameterNames_78129715\target\classes started by Alexander in C:\Users\Alexander\Documents\java-src\SO_AJ_Spring61ParameterNames_78129715)
2024-03-09T14:53:30.329+01:00  INFO 14188 --- [           main] com.example.Application                  : No active profile set, falling back to 1 default profile: "default"
2024-03-09T14:53:31.201+01:00  INFO 14188 --- [           main] com.example.Application                  : Started Application in 1.193 seconds (process running for 1.734)
execution(void com.example.SampleService.doSomething(int,String,Object))
[foo, bar, zot]
Doing something in service method
execution(void com.example.GroovyService.doSomething(int,String,Object))
[foo, bar, zot]
Doing something in Groovy service method

Spring Boot 3.2.3, Spring 6.1.4, JDK 21, Groovy 4.0.19.


Обновлять:

  • Мой репродуктор можно найти в этом репозитории GitHub. Ветка master содержит показанное здесь смешанное решение Java и Groovy, а ветка pure-groovy — вариант только для Groovy.

  • Для решения проблемы, связанной с тем, что сохранение параметров в байт-коде не импортируется правильно в IntelliJ IDEA, я только что создал проблему IDEA-348776. Но это проблема только IDE, приведенное выше решение Maven по-прежнему работает как для смешанных проектов Java и Groovy, так и для чисто проектов Groovy.

Спасибо. Мы используем Groovy, а не плагин Java maven. И у нас уже есть <parameters>true… но все равно не работает.

bytor99999 09.03.2024 13:16

Почему вы не упомянули этот факт в своем вопросе? Там тоже нет соответствующего тега? Я думаю, это очень важно. Если это не сработает, смотрите не на Spring, а на параметры компилятора Groovy. Я только что доказал вам, что в Spring это работает, если файлы классов содержат необходимую информацию.

kriegaex 09.03.2024 13:57

Я добавил в эту смесь службу Groovy и GMavenPlus, и она работает безупречно при запуске приложения с помощью Exec Maven, см. мой обновленный ответ. Что я заметил, так это то, что IntelliJ IDEA находит параметры только при запуске программы после компиляции Maven. Но при перекомпиляции в IDE с нуля в именах параметров выводится значение null. У меня не так уж много опыта работы с Groovy, но, вероятно, нужно как-то указать конфигурации компилятора IDE, чтобы она поступала правильно. Как опытный пользователь Groovy, вы, вероятно, сможете узнать, как это делается. Кажется, он не генерирует заглушки.

kriegaex 09.03.2024 14:59

А может просто использовать Groovy Eclipse Compiler вместо Groovyc через GMavenPlus, тогда заглушки, насколько я помню, не нужны. Я всегда компилирую свои тесты Spock с помощью GrEclipse. Только для этого примера я использовал GMavenPlus, потому что, наверное, он более популярен. Но я предпочитаю GrEclipse.

kriegaex 09.03.2024 15:03

Спасибо за ответы, но для нас проблема скорее весна. Я назвал все @RequestParam("nameHere"), чтобы решить проблему с -parameters. Но в случае SpEL и AOP это не помогает. Но у вас есть <compilerArgs> <arg>-параметры</arg> </compilerArgs> И это отличается от того, что есть у меня, поэтому я попробую то, что у вас есть, и посмотрю, что произойдет. Спасибо.

bytor99999 09.03.2024 21:32

Нет, это не часть плагина GMavenPlus. И я могу выполнить чистую установку mvn, и технически мне не понадобится «nameHere» для RequestParam, но это все равно не решит проблему AOP, когда аргументы не находятся в объекте JoinPoint. Я думаю, что собираюсь провести рефакторинг всего подхода АОП/пользовательских аннотаций. Либо непосредственно в методах службы, либо каким-либо другим способом получить значения в методе аспекта/совета. Спасибо за ваши рекомендации и помощь.

bytor99999 09.03.2024 21:35

Проблема в том, чтобы сидеть перед компьютером, извините за это. Обратите внимание на два разных способа указать генерацию имени параметра для компилятора Maven и GMaven+. Просто чтобы доказать, что вы ошибаетесь, я даже реорганизовал все свои классы Java из примера в моем ответе в чистый Groovy, и он по-прежнему работает в Maven. Вам не нужно проводить рефакторинг, вам нужно исправить конфигурацию сборки. Упрямое обвинение Spring не затрагивает основную причину вашей проблемы. Я опубликовал доказательство того, что это работает так, как я описал, вы только утверждаете, что это не так.

kriegaex 10.03.2024 07:38

Как насчет публикации минимального воспроизводителя вашей проблемы на GitHub вместо того, чтобы заставлять других людей, которые хотят помочь вам, гоняться за хвостом из-за вашей неполной информации?

kriegaex 10.03.2024 07:39

Обратите внимание на ссылки на мой репозиторий GitHub и недавно созданную проблему IntelliJ IDEA в обновленном ответе.

kriegaex 10.03.2024 08:26

Мне жаль, что я вас расстраиваю, вы мне очень помогаете, и я это ценю. Я добавляю плагин компилятора Maven, соответствующий вашему решению GitHub, и сообщу вам об этом через пару минут.

bytor99999 11.03.2024 15:06

Идеальный. Добавление плагина компилятора Maven с помощью GMaven+ Works. Большое спасибо за ваше терпение и помощь.

bytor99999 11.03.2024 15:11

На самом деле, это не сработало до конца. Но речь идет не о компиляции аргументов, которая, кажется, работает, но теперь речь идет о Spring AOP, поскольку getParametersNames() больше не доступен в объекте Signature. Я найду решение этой проблемы в другом месте, сделаю это отдельным постом. Но в этом посте, касающемся изменения и необходимости -параметров, это решено. Спасибо.

bytor99999 11.03.2024 15:17

Опять же, вы не внимательно изучили мой пример кода. Пожалуйста, используйте ((MethodSignature) joinPoint.getSignature()).getParameterNames(). Это AspectJ API, а не Spring API, и он не изменился, потому что AspectJ — это даже не часть Spriung, а самостоятельный проект. Просто используйте правильный API.

kriegaex 11.03.2024 15:43

Я пробовал это раньше, и это не сработало. Он возвращает ноль. Я прекрасно понимаю, что под каким проектом. «Однако метод getParameterNames() больше недоступен, и если вы приведете getSignature к MethodSignature, getParameterNames теперь вернет значение null».

bytor99999 11.03.2024 16:10

Не знаю, почему в вашем образце это работает, а в нашем приложении нет. Я добавил плагин в файл pom, использовал тот же код, но для имен параметров все равно получаю нулевое значение.

bytor99999 11.03.2024 16:25

Также реализацией MethodSignature (интерфейс в AspectJ) является MethodInvocationJoinPoint, который находится в пакете org.springframework.aop.aspectj; Таким образом, хотя интерфейс находится в одном проекте, реализация — в Spring. И теперь, проходя через код Spring, теперь он возвращает имена аргументов, тогда как всего 2 минуты назад с тем же кодом этого не было. Я буквально ничего не менял и теперь все работает. Спасибо.

bytor99999 11.03.2024 16:52

За эти 2 минуты все, что я сделал, это нашел MethodInvocateJoinPoint, затем в IJ загрузил исходники, чтобы я мог установить точку останова в этом классе в методе getParameterNames() в первой строке. Запустил пользовательский интерфейс, который, как я знал, вызывает метод @Before, и он начал возвращать имена параметров после простого выполнения кода.

bytor99999 11.03.2024 16:59

Другие вопросы по теме

Groovy-скрипт для преобразования XML в JSON и форматирования даты из дд-мм-гггг в гггг-мм-дд
Скрипт Powershell в общей библиотеке Jenkins groovy
Как проверить/игнорировать необязательное значение при его проверке с помощью процессора «Проверить CSV» в Apache NiFi?
Nextflow Pipeline: эффективно обрабатывайте геномные области, хранящиеся в нескольких файлах, и затем объединяйте результаты, отслеживая файлы
Переменная, повторяемая из массива в сценарии Jenkins Groovy, не отображает свое значение внутри команды оболочки
Команда оболочки, преобразующая дату и время в секунды в Jenkins Groovy, всегда возвращает одно и то же значение
Проблема в сценарии JSR223. JSR223 Sampler:javax.script.ScriptException: groovy.lang.MissingMethodException: нет подписи метода:
Рендеринг набора результатов Groovy Sql в JSON через JsonBuilder
Проблема в сценарии JSR223. JSR223 Sampler groovy.lang.MissingPropertyException: нет такого свойства: длина для класса: java.lang.String
Рендеринг набора результатов Groovy Sql в XML через MarkupBuilder