Affects: 5.2.8.RELEASE
Hello, I have a problem with correctly resolving annotations data when the default value
field is involved. I've created a shortcut annotation:
@PutJsonMapping
import org.springframework.core.annotation.AliasFor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
public @interface PutJsonMapping {
@AliasFor(annotation = RequestMapping.class)
String name() default "";
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] value() default {};
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};
@AliasFor(annotation = RequestMapping.class)
String[] produces() default MediaType.APPLICATION_JSON_VALUE;
}
I use it on a method and then I try to inspect the annotation values like this
var requestMapping = AnnotatedElementUtils.getMergedAnnotationAttributes(method, RequestMapping.class);
When I use it like this
@PutJsonMapping("/{token}")
public ResponseEntity<Object> confirm()
The requestMapping has empty path and value fields
If I inspect the method reflection, I see that the value is present
But if I change the usage to
@PutJsonMapping(path = "/{token}")
public ResponseEntity<Object> confirm()
now the aliasing starts working as expected
IMHO the @AliasFor
should work the way I tried to use it.
The framework as a whole behaves correctly, so it has to be resolving the path somehow, it's just that when I try to inspect the method annotations using AnnotatedElementUtils
, then it behaves unexpectedly.
Also, since the RequestMapping
has aliased value
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
I would expect this to work even just like this (without explicitly writing the attribute = "path"
)
public @interface PutJsonMapping {
@AliasFor(annotation = RequestMapping.class)
String name() default "";
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
Comment From: sbrannen
Did this work for you prior to Spring Framework 5.2?
Comment From: fprochazka
@sbrannen I vaguely recall that I had a similar problem few versions back, but I ended up not needing it, and I shamefully have to admit, that I was too bussy to report it.
Comment From: flozano
Is this a regression since 5.2.7.RELEASE? I'm having very random test failures in a big test-suite that makes substantial use of @AliasFor
and that started happening just after upgrading to 5.2.8.RELEASE. Still investigating, but if this is a regression since 5.2.7.RELEASE, it could help me narrow down the cause.
Comment From: sbrannen
The following test class passes against master
(i.e., 5.3.4 snapshots).
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import static org.assertj.core.api.Assertions.assertThat;
class MergedAnnotationAttributesTests {
@Test
@PutJsonMapping("/test")
void mergedAnnotationAttributes(TestInfo testInfo) {
Method method = testInfo.getTestMethod().get();
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(method,
RequestMapping.class);
assertThat(attributes.getStringArray("value")).containsExactly("/test");
assertThat(attributes.getStringArray("path")).containsExactly("/test");
assertThat(attributes.get("value")).isEqualTo(new String[] {"/test"});
assertThat(attributes.get("path")).isEqualTo(new String[] {"/test"});
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
@interface PutJsonMapping {
@AliasFor(annotation = RequestMapping.class) // , attribute = "path")
String[] value() default {};
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
}
}
I'll see what happens with previous 5.3.x versions and various 5.2.x versions.
Comment From: sbrannen
@fprochazka, the above MergedAnnotationAttributesTests
class passes when executed against v5.2.1.RELEASE
, v5.2.7.RELEASE
, v5.2.8.RELEASE
, v5.2.12.RELEASE
, and 5.3.4
snapshots (i.e., master
).
Thus I have not been able to reproduce the behavior you have described.
Are you able to provide a sample project (such as a GitHub repository or ZIP file) that reproduces the behavior you described?
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.