Начиная с версии 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, чтобы он работал при локальном запуске сервера через службы.
Я только что заметил ваше обновление. Что именно остается проблемой после того, как вы уже приняли мой ответ, который доказывает, что он надежно работает в Maven? Вы говорите о проблеме IntelliJ, которую я для вас создал? В этом случае проблема будет не в том, что описано и отмечено здесь, а в отдельной проблеме, связанной с IDE. Ваше описание и комментарии настолько размыты, что трудно понять, в чем заключается ваша реальная проблема.
Тот факт, что def argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames() одна установка mvn возвращает имена параметров, следующая установка mvn возвращает ноль. Тот же метод, он всегда должен возвращать имена параметров, но в некоторых сборках он не работает, все они имеют -параметры, установленные в конфигурации плагина, поэтому ничего не меняется ни в одной сборке, ни в следующей.
С моим примером проекта такого никогда не происходит. Если это произойдет в вашем проекте, задайте новый вопрос и разместите ссылку на полный минимальный репродуктор на GitHub. Никто не сможет отладить ваши недоказанные утверждения. До тех пор, пока не будут получены дополнительные доказательства обратного, я предполагаю, что проблема кроется в компьютере.
Я не могу создать минимальный воспроизводитель. Ненавижу, когда меня спрашивают, что это не ваша вина, но не все, что происходит, может быть создано с помощью минимального воспроизводителя, это ПРОСТО происходит с полной кодовой базой. «Проблема стоит перед компьютером». Ф-У, ты ничего обо мне не знаешь. Это совершенно грубо и неуместно.
Пожалуйста, не говорите «Я не могу», если правда в том, что «Я не хочу». Или, если вы действительно не можете, воздержитесь от названия себя разработчиком программного обеспечения. Иногда это трудоемкий, но на самом деле довольно тривиальный и механический процесс постепенного удаления элементов из вашего проекта, пока не останется минимальный воспроизводитель. Столь же тривиален процесс анонимизации минимального кода без раскрытия каких-либо секретов компании. Мне не нужно ничего знать о вас, чтобы сделать такое заявление.
Ну, очевидно, ваш ответ не работает. И я не единственный в моей команде, у кого возникла эта проблема.
Я объясняю снова и снова... «def argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames() одна установка mvn возвращает имена параметров, следующая установка mvn возвращает ноль». Таким образом, один раз он возвращает список имен аргументов, а затем в другой раз, после выключения сервера и его резервного запуска, он возвращает значение null для того же метода, который он рекомендует. Часть меня теперь думает, что IJ не перестраивает с использованием -параметров, хотя в настройках моего компилятора установлено добавление -параметров при компиляции.
А я не могу, что касается строительства небольшого проекта. Зачастую подобные проблемы невозможно воспроизвести на мелкой стороне, хотя в нашем приложении это МНОГО случается со всеми разработчиками серверной части. Не каждую проблему можно показать в небольшом простом проекте.
Это становится еще более странным, когда у меня был один метод той же службы, рекомендованный АОП, где вызов getParameters() возвращает значение null, но другие методы в той же службе, рекомендованные АОП, возвращают параметры метода. Но я определенно думаю, что решил проблему. И это проблема IntelliJ. Я изменил настройку компилятора Java, включив при необходимости параметры -parameters, но есть еще одно место, которое необходимо изменить, а именно: Build Tools-Maven-Runner. Делегирование действий сборки/запуска IDE в maven необходимо проверить, и это работает.
Если этот флажок снят, и вы измените класс службы так, что IJ придется его снова скомпилировать, он не будет делать этого с параметрами -parameters, даже если у вас есть настройки компилятора Java, настроенные на его добавление. Если он установлен, это означает, что Maven скомпилирует его, и предложенная конфигурация maven, подобная приведенной ниже, означает, что он будет скомпилирован с параметрами -parameters.
И мне пришлось решать эту проблему самому. Последняя проблема, которая у меня возникла с IDE. В котором никакая репродукция не показала бы этого.
Ваша проблема с IDE была дополнительным вопросом, который вы отредактировали после того, как я уже ответил на исходный вопрос Maven. Здесь это было не по теме, и вам следовало задать новый вопрос, как это принято на Stack Overflow. Расползание прицела здесь считается плохим стилем. Одна проблема, один вопрос. В исходном вопросе даже не упоминаются «IDE», «IntelliJ» и als не помечены соответствующим образом.
Как я уже сказал, я даже уже создал задачу IDEA для вашей новой проблемы. Я также знаю обходной путь простого делегирования полномочий от IDEA к Maven и мог бы рассказать вам. Но вы до самого конца упорно твердили, что мое Maven-решение у вас не работает, поэтому я не упомянул обходной путь, потому что у вас создалось впечатление, что ваш собственный POM все еще не исправлен. Вам просто нужно научиться лучше задавать вопросы и быть точным в своих вопросах и комментариях, если их о чем-то спрашивают. Таким образом, вы просто тратите драгоценное время всех, включая свое собственное.
Примером простого способа улучшить вопрос или последующий комментарий могло бы быть что-то вроде: «Решение Maven от kriegaex работает нормально, но у меня все еще возникают проблемы при перекомпиляции в IntelliJ IDEA». Но нигде вы не сказали ничего даже подобного. Вместо этого вы сначала приняли, а затем отклонили мой ответ Maven, указав, что решение Maven вам не помогло. Может ли врач помочь вылечить боль в спине у пациента, если больной уверяет, что у него болит палец, а о спине даже не упоминает?
Спасибо. Я обязательно сделаю это в следующий раз.
даже с параметрами -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… но все равно не работает.
Почему вы не упомянули этот факт в своем вопросе? Там тоже нет соответствующего тега? Я думаю, это очень важно. Если это не сработает, смотрите не на Spring, а на параметры компилятора Groovy. Я только что доказал вам, что в Spring это работает, если файлы классов содержат необходимую информацию.
Я добавил в эту смесь службу Groovy и GMavenPlus, и она работает безупречно при запуске приложения с помощью Exec Maven, см. мой обновленный ответ. Что я заметил, так это то, что IntelliJ IDEA находит параметры только при запуске программы после компиляции Maven. Но при перекомпиляции в IDE с нуля в именах параметров выводится значение null. У меня не так уж много опыта работы с Groovy, но, вероятно, нужно как-то указать конфигурации компилятора IDE, чтобы она поступала правильно. Как опытный пользователь Groovy, вы, вероятно, сможете узнать, как это делается. Кажется, он не генерирует заглушки.
А может просто использовать Groovy Eclipse Compiler вместо Groovyc через GMavenPlus, тогда заглушки, насколько я помню, не нужны. Я всегда компилирую свои тесты Spock с помощью GrEclipse. Только для этого примера я использовал GMavenPlus, потому что, наверное, он более популярен. Но я предпочитаю GrEclipse.
Спасибо за ответы, но для нас проблема скорее весна. Я назвал все @RequestParam("nameHere"), чтобы решить проблему с -parameters. Но в случае SpEL и AOP это не помогает. Но у вас есть <compilerArgs> <arg>-параметры</arg> </compilerArgs> И это отличается от того, что есть у меня, поэтому я попробую то, что у вас есть, и посмотрю, что произойдет. Спасибо.
Нет, это не часть плагина GMavenPlus. И я могу выполнить чистую установку mvn, и технически мне не понадобится «nameHere» для RequestParam, но это все равно не решит проблему AOP, когда аргументы не находятся в объекте JoinPoint. Я думаю, что собираюсь провести рефакторинг всего подхода АОП/пользовательских аннотаций. Либо непосредственно в методах службы, либо каким-либо другим способом получить значения в методе аспекта/совета. Спасибо за ваши рекомендации и помощь.
Проблема в том, чтобы сидеть перед компьютером, извините за это. Обратите внимание на два разных способа указать генерацию имени параметра для компилятора Maven и GMaven+. Просто чтобы доказать, что вы ошибаетесь, я даже реорганизовал все свои классы Java из примера в моем ответе в чистый Groovy, и он по-прежнему работает в Maven. Вам не нужно проводить рефакторинг, вам нужно исправить конфигурацию сборки. Упрямое обвинение Spring не затрагивает основную причину вашей проблемы. Я опубликовал доказательство того, что это работает так, как я описал, вы только утверждаете, что это не так.
Как насчет публикации минимального воспроизводителя вашей проблемы на GitHub вместо того, чтобы заставлять других людей, которые хотят помочь вам, гоняться за хвостом из-за вашей неполной информации?
Обратите внимание на ссылки на мой репозиторий GitHub и недавно созданную проблему IntelliJ IDEA в обновленном ответе.
Мне жаль, что я вас расстраиваю, вы мне очень помогаете, и я это ценю. Я добавляю плагин компилятора Maven, соответствующий вашему решению GitHub, и сообщу вам об этом через пару минут.
Идеальный. Добавление плагина компилятора Maven с помощью GMaven+ Works. Большое спасибо за ваше терпение и помощь.
На самом деле, это не сработало до конца. Но речь идет не о компиляции аргументов, которая, кажется, работает, но теперь речь идет о Spring AOP, поскольку getParametersNames() больше не доступен в объекте Signature. Я найду решение этой проблемы в другом месте, сделаю это отдельным постом. Но в этом посте, касающемся изменения и необходимости -параметров, это решено. Спасибо.
Опять же, вы не внимательно изучили мой пример кода. Пожалуйста, используйте ((MethodSignature) joinPoint.getSignature()).getParameterNames(). Это AspectJ API, а не Spring API, и он не изменился, потому что AspectJ — это даже не часть Spriung, а самостоятельный проект. Просто используйте правильный API.
Я пробовал это раньше, и это не сработало. Он возвращает ноль. Я прекрасно понимаю, что под каким проектом. «Однако метод getParameterNames() больше недоступен, и если вы приведете getSignature к MethodSignature, getParameterNames теперь вернет значение null».
Не знаю, почему в вашем образце это работает, а в нашем приложении нет. Я добавил плагин в файл pom, использовал тот же код, но для имен параметров все равно получаю нулевое значение.
Также реализацией MethodSignature (интерфейс в AspectJ) является MethodInvocationJoinPoint, который находится в пакете org.springframework.aop.aspectj; Таким образом, хотя интерфейс находится в одном проекте, реализация — в Spring. И теперь, проходя через код Spring, теперь он возвращает имена аргументов, тогда как всего 2 минуты назад с тем же кодом этого не было. Я буквально ничего не менял и теперь все работает. Спасибо.
За эти 2 минуты все, что я сделал, это нашел MethodInvocateJoinPoint, затем в IJ загрузил исходники, чтобы я мог установить точку останова в этом классе в методе getParameterNames() в первой строке. Запустил пользовательский интерфейс, который, как я знал, вызывает метод @Before, и он начал возвращать имена параметров после простого выполнения кода.
Поможет ли это вам: сохранить имя параметра ?