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

Spring AnnotatedElementUtils.getMergedAnnotationAttributes() does not work as expected for 'value' annotation attribute

If I inspect the method reflection, I see that the value is present

annotations

But if I change the usage to

@PutJsonMapping(path = "/{token}")
public ResponseEntity<Object> confirm()

now the aliasing starts working as expected

Spring AnnotatedElementUtils.getMergedAnnotationAttributes() does not work as expected for 'value' annotation attribute

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.