Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@heliang666s
Copy link
Member

What is the purpose of the change?

Support @ConditionalOnMissingBean for @DubboService #15814

@codecov-commenter
Copy link

codecov-commenter commented Dec 15, 2025

Codecov Report

❌ Patch coverage is 16.41791% with 56 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.74%. Comparing base (be40746) to head (541dcef).
⚠️ Report is 4 commits behind head on 3.3.

Files with missing lines Patch % Lines
...ory/annotation/ServiceAnnotationPostProcessor.java 16.41% 46 Missing and 10 partials ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##                3.3   #15875   +/-   ##
=========================================
  Coverage     60.74%   60.74%           
- Complexity    11754    11759    +5     
=========================================
  Files          1949     1949           
  Lines         88898    88965   +67     
  Branches      13407    13432   +25     
=========================================
+ Hits          53998    54046   +48     
- Misses        29337    29355   +18     
- Partials       5563     5564    +1     
Flag Coverage Δ
integration-tests-java21 32.20% <0.00%> (-0.02%) ⬇️
integration-tests-java8 32.30% <0.00%> (-0.09%) ⬇️
samples-tests-java21 32.20% <0.00%> (+0.08%) ⬆️
samples-tests-java8 29.69% <0.00%> (+<0.01%) ⬆️
unit-tests-java11 59.03% <16.41%> (+0.02%) ⬆️
unit-tests-java17 58.48% <16.41%> (-0.04%) ⬇️
unit-tests-java21 58.49% <16.41%> (-0.02%) ⬇️
unit-tests-java25 58.43% <16.41%> (-0.03%) ⬇️
unit-tests-java8 58.99% <16.41%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@zrlw
Copy link
Contributor

zrlw commented Dec 18, 2025

add test cases to check its effectiveness?

@heliang666s heliang666s force-pushed the conditional-on-missing-bean-for-dubbo-service branch from 8dafa89 to 41922ef Compare January 25, 2026 11:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds support for Spring Boot's @ConditionalOnMissingBean annotation when used with @DubboService on Java config @bean methods. This addresses issue #15814, enabling developers to conditionally register Dubbo services based on the presence or absence of other beans in the application context.

Changes:

  • Added logic in ServiceAnnotationPostProcessor to detect and respect @ConditionalOnMissingBean annotations
  • Implemented conditional checking that prevents ServiceBean registration when matching beans exist
  • Added comprehensive test cases to verify the conditional behavior works correctly

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
ServiceAnnotationPostProcessor.java Added shouldSkipDueToConditionalOnMissingBean() and hasExistingBeanOfType() methods to check for @ConditionalOnMissingBean and skip ServiceBean registration when the condition is not met
JavaConfigBeanTest.java Added test cases testConditionalOnMissingBeanForDubboService() and testConditionalOnMissingBeanForDubboServiceWhenMissing() along with supporting configuration classes to verify the feature works correctly

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +688 to +693
if (beanNames != null) {
for (String beanName : beanNames) {
if (hasExistingBeanName(beanName, refServiceBeanName)) {
return true;
}
}
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The code checks if beanNames is not null but doesn't check if it's an empty array before iterating. While iterating over an empty array is safe and won't cause errors, it would be more explicit and consistent with the beanTypes handling (line 697) to check for both null and empty array. Consider adding a length check: if (beanNames != null && beanNames.length > 0) for consistency and clarity.

Copilot uses AI. Check for mistakes.
Comment on lines +722 to +727
if (beanTypes == null || beanTypes.length == 0) {
return false;
}

for (Class<?> beanType : beanTypes) {
if (hasExistingBeanOfType(beanType, refServiceBeanName)) {
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The implementation doesn't handle the default behavior of @ConditionalOnMissingBean when no value, type, or name is specified. According to Spring Boot's @ConditionalOnMissingBean contract, when no parameters are provided, it should default to the return type of the annotated method. Currently, when no bean types are found (lines 722-723), the method returns false, which means the bean will always be registered even if a bean of the same return type already exists.

To fix this, you should check if no attributes were specified and default to the return type of the factory method. You can use SpringCompatUtils.getFactoryMethodReturnType to get the return type and check if a bean of that type already exists.

Suggested change
if (beanTypes == null || beanTypes.length == 0) {
return false;
}
for (Class<?> beanType : beanTypes) {
if (hasExistingBeanOfType(beanType, refServiceBeanName)) {
if (beanTypes != null && beanTypes.length > 0) {
for (Class<?> beanType : beanTypes) {
if (hasExistingBeanOfType(beanType, refServiceBeanName)) {
return true;
}
}
} else {
// No explicit name, value, or type specified: default to the factory method's return type
Class<?> returnType = SpringCompatUtils.getFactoryMethodReturnType(beanDefinition);
if (returnType != null && hasExistingBeanOfType(returnType, refServiceBeanName)) {

Copilot uses AI. Check for mistakes.
if (!ClassUtils.isPresent(resolvedName, classLoader)) {
continue;
}
resolvedTypes.add(resolveClassName(resolvedName, classLoader));
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The call to resolveClassName at line 715 could throw IllegalArgumentException or LinkageError if the class cannot be loaded, even though ClassUtils.isPresent checked for the class presence. This can happen due to ClassLoader issues or race conditions. Consider wrapping this call in a try-catch block to handle potential exceptions gracefully and continue processing other type names instead of failing the entire operation.

Suggested change
resolvedTypes.add(resolveClassName(resolvedName, classLoader));
try {
resolvedTypes.add(resolveClassName(resolvedName, classLoader));
} catch (IllegalArgumentException | LinkageError ex) {
// Skip this type if it cannot be resolved at this point
}

Copilot uses AI. Check for mistakes.
Comment on lines +129 to +165
@Test
void testConditionalOnMissingBeanForDubboService() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConditionalTestConfiguration.class,
ExistingServiceConfiguration.class,
ConditionalServiceConfiguration.class);
try {
Assertions.assertFalse(context.containsBeanDefinition("conditionalDemoService"));

Map<String, ServiceBean> serviceBeans = context.getBeansOfType(ServiceBean.class);
Assertions.assertEquals(0, serviceBeans.size());

Map<String, DemoService> demoServices = context.getBeansOfType(DemoService.class);
Assertions.assertEquals(1, demoServices.size());
Assertions.assertNotNull(demoServices.get("existingDemoService"));
} finally {
context.close();
}
}

@Test
void testConditionalOnMissingBeanForDubboServiceWhenMissing() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConditionalTestConfiguration.class, ConditionalServiceConfiguration.class);
try {
Assertions.assertTrue(context.containsBeanDefinition("conditionalDemoService"));

Map<String, ServiceBean> serviceBeans = context.getBeansOfType(ServiceBean.class);
Assertions.assertEquals(1, serviceBeans.size());

Map<String, DemoService> demoServices = context.getBeansOfType(DemoService.class);
Assertions.assertEquals(1, demoServices.size());
Assertions.assertNotNull(demoServices.get("conditionalDemoService"));
} finally {
context.close();
}
}
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The test coverage is missing several important edge cases for the @ConditionalOnMissingBean feature:

  1. Testing @ConditionalOnMissingBean without any parameters (should default to return type)
  2. Testing with the 'name' attribute to check bean by name
  3. Testing with the 'type' attribute using string class names
  4. Testing behavior when multiple beans of the target type exist
  5. Testing interaction with bean aliases

Consider adding additional test methods to cover these scenarios to ensure the implementation handles all supported @ConditionalOnMissingBean configurations correctly.

Copilot uses AI. Check for mistakes.
if (shouldSkipDueToConditionalOnMissingBean(refServiceBeanName, refServiceBeanDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Skip registering ServiceBean for bean [" + refServiceBeanName
+ "] due to @ConditionalOnMissingBean condition not satisfied");
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The debug message at line 623-624 says "condition not satisfied" which is somewhat misleading. When @ConditionalOnMissingBean condition is "not satisfied", it means a bean of the specified type already exists, so the new bean should not be registered. However, the phrasing "condition not satisfied" might suggest something went wrong. Consider rewording it to be more clear, such as "bean already exists" or "condition evaluated to false - bean exists". For example: "Skip registering ServiceBean for bean [" + refServiceBeanName + "] due to @ConditionalOnMissingBean - bean of required type already exists"

Suggested change
+ "] due to @ConditionalOnMissingBean condition not satisfied");
+ "] due to @ConditionalOnMissingBean - bean of required type already exists");

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants