Skip to content

Add support for JSR-330 and Jakarta @Inject for autowiring test constructors #29851

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

FlorianLehmann
Copy link
Contributor

@FlorianLehmann FlorianLehmann commented Jan 18, 2023

Overview

Spring 3.0 added support for JSR-330. However, the spring-test module is only supporting @Autowired for dependency injection.

This PR intends to add @Inject support for spring-test. Since Spring Framework 6 still supports @javax.inject.Inject in addition to @jakarta.inject.Inject, this PR reintroduces support for @javax.inject.Inject in spring-test as well.

Examples

The following test passes:

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import static org.assertj.core.api.Assertions.assertThat;

@SpringJUnitConfig
public class FooTests {

	private final String foo;

	@Autowired
	public FooTests(String foo) {
		this.foo = foo;
	}

	@Test
	public void beanInjected() {
		assertThat(this.foo).isEqualTo("foo");
	}

	@Configuration
	static class Config {

		@Bean
		String foo() {
			return "foo";
		}

	}
}

However, if @Autowired is replaced with @javax.inject.Inject the test fails:

package com.example.demo;

import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import static org.assertj.core.api.Assertions.assertThat;

@SpringJUnitConfig
public class FooTests {

	private final String foo;

	@Inject
	public FooTests(String foo) {
		this.foo = foo;
	}

	@Test
	public void beanInjected() {
		assertThat(this.foo).isEqualTo("foo");
	}

	@Configuration
	static class Config {

		@Bean
		String foo() {
			return "foo";
		}

	}
}

Error

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.lang.String foo] in constructor [public com.example.demo.FooTests(java.lang.String)].

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jan 18, 2023
@sbrannen sbrannen changed the title Add support for JSR-330 @Inject annotation in spring-test Reintroduce support for the JSR-330 @Inject annotation in spring-test Jan 19, 2023
@sbrannen sbrannen changed the title Reintroduce support for the JSR-330 @Inject annotation in spring-test Reintroduce support for JSR-330 @javax.inject.Inject in spring-test Jan 19, 2023
@sbrannen sbrannen added in: test Issues in the test module type: enhancement A general enhancement labels Jan 19, 2023
@sbrannen sbrannen self-assigned this Jan 19, 2023
@sbrannen sbrannen changed the title Reintroduce support for JSR-330 @javax.inject.Inject in spring-test Add support for JSR-330 and Jakarta @Inject for autowiring test constructors Jan 19, 2023
@sbrannen
Copy link
Member

I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

@sbrannen
Copy link
Member

Hi @FlorianLehmann,

Congratulations on submitting your first PR for the Spring Framework! 👍

However, the spring-test module is only supporting @Autowired for dependency injection.

That's not entirely true.

The Spring TestContext Framework supports whatever DI annotations are supported by AutowiredAnnotationBeanPostProcessor, which includes @Autowired and @Value as well as @jakarta.inject.Inject and @javax.inject.Inject (if the latter two are available on the classpath).

Thus, you are free to use @Inject for fields and methods in your test classes.

The only restriction regarding @Autowired vs @Inject is that @Inject cannot be used for autowiring test class constructors when using JUnit Jupiter (but @Autowired can).

In addition, @Inject cannot be used to autowire a particular constructor or method argument simply because @Inject is configured with @Target({ METHOD, CONSTRUCTOR, FIELD }). So that limitation is inherent to @Inject and therefore out of Spring's control.

If I recall correctly, the latter is the reason that we decided not to support @Inject for JUnit Jupiter features: we wanted to support @Autowired which can be used consistently for test class constructors as well as individual constructor/method arguments.

However, we will consider adding support for @Inject for test class constructors, and I have changed the title of this issue to reflect that.

@sbrannen sbrannen marked this pull request as draft January 19, 2023 10:35
@FlorianLehmann
Copy link
Contributor Author

FlorianLehmann commented Jan 22, 2023

Hi @sbrannen,

I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

Thank you I'll definitely have a look.

In addition, @Inject cannot be used to autowire a particular constructor or method argument simply because @Inject is configured with @Target({ METHOD, CONSTRUCTOR, FIELD }). So that limitation is inherent to @Inject and therefore out of Spring's control.

I believe the same limitation applies for "normal" constructor or method arguments. The idea of this PR is to remove the discrepancy between tests and "normal" code when autowiring a constructor using @Inject.

However, we will consider adding support for @Inject for test class constructors, and I have changed the title of this issue to reflect that.

👍

Thank you again for your comments.

@sbrannen sbrannen self-requested a review January 22, 2023 15:45
@sbrannen sbrannen removed the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 6, 2023
@sbrannen sbrannen added this to the 6.1.x milestone Apr 6, 2023
@sbrannen sbrannen modified the milestones: 6.1.x, 6.1.0-RC1 Aug 19, 2023
Copy link
Member

@sbrannen sbrannen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the proposal looks good in general, though I might revise it a bit after merging into main.

@sbrannen
Copy link
Member

sbrannen commented Sep 8, 2023

This has been merged into main in 8dd857a and revised in dfea3d0, for inclusion in Spring Framework 6.1.

Thanks for your contribution, @FlorianLehmann! 🍃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants