Why Spring 6 deals with plain Record as a bean

Viewed 124

I created a simple Spring WebMvc/Data Jdbc to experience the newest Spring 6.

  • Java 17
  • Spring 6.0.0-M2
  • Spring Data Jdbc 2022.0.0

There is a record class for DTOs. This record is NOT annotated with any Spring annotations.

public record CreatePostCommand(String title, String content) {
}

There is a RouterFunction to handle the request.

@Component
@RequiredArgsConstructor
public class PostHandler {

    private final PostRepository posts;

    public ServerResponse all(ServerRequest req) {
        return ok().body(this.posts.findAll());
    }

    @SneakyThrows
    public ServerResponse create(ServerRequest req) {
        var data = req.body(CreatePostCommand.class);
        var saved = this.posts.save(Post.builder().title(data.title()).content(data.content()).build());
        return created(URI.create("/posts/" + saved.getId())).build();
    }
//...
}

I wrote a test to verify the REST APIs.

    @Test
    public void getGetAllPosts() throws Exception {
        when(this.posts.findAll())
                .thenReturn(List.of(
                                Post.builder().title("test").content("content of test1").build(),
                                Post.builder().title("test2").content("content of test2").build()
                        )
                );

        this.rest.perform(get("/posts").accept(MediaType.APPLICATION_JSON))
                .andExpectAll(
                        status().isOk(),
                        jsonPath("$.size()", equalTo(2))
                );

        verify(this.posts, times(1)).findAll();
        verifyNoMoreInteractions(this.posts);
    }

When running the test, it failed.

java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'createPostCommand' defined in file [D:\hantsylabs\spring6-sandbox\data-jdbc\
target\classes\com\example\demo\web\CreatePostCommand.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.No
SuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}        
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowir
e candidate. Dependency annotations: {}

The detailed test failure log can be found on Github actions, check here: https://github.com/hantsy/spring6-sandbox/runs/4989195307?check_suite_focus=true#step:7:179

I defined a Filter attribute in the @ComponentScan annotation in the web configuration.

@ComponentScan(
        basePackageClasses = WebConfig.class,
        useDefaultFilters = false,
        includeFilters = {
                @ComponentScan.Filter(type = FilterType.REGEX, pattern ="^(com\\.example\\.demo\\.web\\.)(.+)$")
        }
)

Update: When changing to the following to exclude the record classes, it works.

@ComponentScan(
        basePackageClasses = WebConfig.class,
        useDefaultFilters = false,
        includeFilters = {
                @ComponentScan.Filter(type = FilterType.REGEX, pattern ="^(com\\.example\\.demo\\.web\\.)(.*Handler)$")
        }
)

I am confused about the filters with regex pattern:

  • It should include all Spring managed beans or any classes matched this pattern? In my mind, I think it should only handle the Spring managed beans.
  • In another example, there is an exclude filter, the result should contains the record classes and some other POJOs, but it does not treat them as Spring beans.
0 Answers
Related