Skip to content

ActiveProfiles not included when using a custom annotation. [SPR-13748] #18321

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

Closed
spring-projects-issues opened this issue Dec 1, 2015 · 12 comments
Assignees
Labels
in: test Issues in the test module status: duplicate A duplicate of another issue

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Dec 1, 2015

Adam Berlin opened SPR-13748 and commented

The following doesn't work:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = SpringApplicationContextLoader.class)
@ReproduceTest.MyActiveProfile
public class ReproduceTest {

    @Autowired
    private String value;

    @Test
    public void itDoesNotPickUpTestPropertiesUsingMetaAnnotation() {
        assertEquals("foo", this.value);
    }

    @ActiveProfiles({"foo"})
    public static @interface MyActiveProfile {
    }

    @Configuration
    @Profile("foo")
    public static class FooConfig {
        @Bean
        public String value() {
            return "foo";
        }
    }
}

Affects: 4.1.8

Issue Links:

@spring-projects-issues
Copy link
Collaborator Author

Adam Berlin commented

If it helps, I worked with Rossen when creating this ticket. He should have additional context.

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

For starters, your example won't work since it does not define the retention policy.

Have you tried the following?

@Retention(RetentionPolicy.RUNTIME)
@ActiveProfiles("foo")
public @interface MyActiveProfile {
}

@spring-projects-issues
Copy link
Collaborator Author

Adam Berlin commented

Adding the retention to this example worked, but I have a more complicated example that does not work:

package holmes.rtvs.repositories;

import org.springframework.test.context.ActiveProfiles;

@ActiveProfiles({"foo"})
public class ReproduceBaseTest {
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = SpringApplicationContextLoader.class)
@ReproduceTest.MyActiveProfile
public class ReproduceTest extends ReproduceBaseTest {

    @Autowired
    private String value;

    @Test
    public void itDoesNotPickUpTestPropertiesUsingMetaAnnotation() {
        assertEquals("bar", this.value);
    }

    @Retention(RetentionPolicy.RUNTIME)
    @ActiveProfiles({"bar"})
    public static @interface MyActiveProfile {
    }

    @Configuration
    @Profile("foo")
    public static class FooConfig {
        @Bean
        public String value() {
            return "foo";
        }
    }

    @Configuration
    @Profile("bar")
    public static class BarConfig {
        @Bean
        public String value() {
            return "bar";
        }
    }
}

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

FYI: this has nothing to do with the testing framework or meta-annotation support. Rather, this is simply a configuration error.

You are defining two beans of the same type with the same name, and you cannot have two of the same thing. So naturally the last one wins. It just so happens that "foo" always wins in this particular case (at least on my JVM).

Annotating your class like this causes it to fail:

@ContextConfiguration

Annotating your class like this causes it to fail:

@ContextConfiguration(classes = {
    ReproduceTest.BarConfig.class,
    ReproduceTest.FooConfig.class })

Annotating your class like this causes it to pass:

@ContextConfiguration(classes = {
    ReproduceTest.FooConfig.class,
    ReproduceTest.BarConfig.class })

I am therefore closing this issue as "Works as Designed".

Regards,

Sam

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

You are defining two beans of the same type with the same name, and you cannot have two of the same thing.

They are two beans of the same type and name but they're included in separate config files each marked with @Profile. In combination with @ActiveProfiles shouldn't only one of them be included. In fact when not using the custom annotation, i.e. using @ActiveProfile, it works.

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

@ActiveProfiles works analogous to setting the spring.profiles.active system property.

In the ReproduceTest example in the comments above, both profiles (i.e., foo and bar) are active, and that's to be expected, since:

  1. ReproduceBaseTest declares @ActiveProfiles("foo")
  2. ReproduceTest declares @ReproduceTest.MyActiveProfile which declares @ActiveProfiles("bar")
  3. As explained in the Javadoc, active profiles are inherited by default within test class hierarchies. If you don't want profiles to be inherited, you can disable this feature.

The end result is that foo and bar are both active profiles; any components that are declared for either of those profiles are thus active in the application context; and for duplicate beans of the same name and type, the last one wins. I demonstrated this above by changing the order in which the @Configuration classes are registered/detected. Again, these are the standard semantics for Spring profiles; the testing framework does not change the semantics for how profiles work.

Does that make things clearer?

@spring-projects-issues
Copy link
Collaborator Author

Sam Brannen commented

In fact when not using the custom annotation, i.e. using @ActiveProfile, it works.

I was not able to reproduce this behavior. So if you can provide an example that demonstrates that the testing framework handles profiles differently than production deployments, that would be a bug, and I'd be more than happy to investigate further.

Thanks,

Sam

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 3, 2015

@spring-projects-issues
Copy link
Collaborator Author

Rossen Stoyanchev commented

Okay here is an example:

@ActiveProfiles(value = "bar")
class ReproduceBaseTest {
}

@Retention(RetentionPolicy.RUNTIME)
@ActiveProfiles(value = "foo", inheritProfiles = false)
@interface MyActiveProfiles {
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@MyActiveProfiles
public class ReproduceTest extends ReproduceBaseTest {

	@Autowired
	private ConfigurableApplicationContext context;

	@Test
	public void itDoesNotPickUpTestPropertiesUsingMetaAnnotation() {
		String[] profiles = this.context.getEnvironment().getActiveProfiles();
		System.out.println(Arrays.toString(profiles));
	}


	@Configuration
	public static class FooConfig {
	}
}

In master it prints "[foo]" correctly. In 4.1.x it prints "[bar]".

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

As a general note, there are quite a few composed annotation scenarios which do not work in the 4.1.x line. As a consequence, at this late point, I'm reluctant to try to address any such issues in 4.1.9. Are we ok with marking this issue as resolved in 4.2?

Juergen

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 3, 2015

Sam Brannen commented

Rossen Stoyanchev, thanks for providing the failing example.

Now it's clear!

This is a duplicate of #17346, which was fixed in 4.2

I am therefore resolving this ticket as a Duplicate.

Regards,

Sam

@spring-projects-issues
Copy link
Collaborator Author

Adam Berlin commented

Ok rstoya05-aop, I think we need to find a better example that drives out this problem. I am still unable to create the meta-annotation that I wanted while using Spring 4.2.

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 status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

2 participants