-
Notifications
You must be signed in to change notification settings - Fork 190
feat: Improve SpringInstantiator #23079
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
base: main
Are you sure you want to change the base?
Conversation
Test Results1 307 files + 1 1 307 suites +1 1h 15m 16s ⏱️ + 1m 19s For more details on these failures, see this check. Results for commit be35435. ± Comparison against base commit dd5ce25. ♻️ This comment has been updated with latest results. |
|
Formatter failed writing comment here automatically. Please run |
tltv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes works well. There's no new tests to verify the feature with primary beans so at minimum I would want to have at least the following unit tests added in vaadin-spring module's tests:
/*
* Copyright 2000-2025 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.flow.spring.i18n;
import jakarta.servlet.ServletException;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
import com.vaadin.flow.di.Instantiator;
import com.vaadin.flow.i18n.I18NProvider;
import com.vaadin.flow.server.InitParameters;
import com.vaadin.flow.spring.instantiator.SpringInstantiatorTest;
@RunWith(SpringRunner.class)
@Import(PrimaryI18NProviderInstantiationTest.I18NTestConfig.class)
public class PrimaryI18NProviderInstantiationTest {
@Autowired
private ApplicationContext context;
@Configuration
@ComponentScan
public static class I18NTestConfig {
}
@Component
public static class I18NTestProvider implements I18NProvider {
@Override
public List<Locale> getProvidedLocales() {
return null;
}
@Override
public String getTranslation(String key, Locale locale,
Object... params) {
return null;
}
}
@Component
public static class I18NTestProvider1 extends I18NTestProvider {
}
@Primary
@Component
public static class PrimaryI18NTestProvider extends I18NTestProvider {
}
public static class DefaultI18NTestProvider extends I18NTestProvider {
}
@Test
public void getI18NProvider_usePrimaryBean() throws ServletException {
Instantiator instantiator = SpringInstantiatorTest
.getService(context, null).getInstantiator();
Assert.assertNotNull(instantiator.getI18NProvider());
Assert.assertEquals(PrimaryI18NTestProvider.class,
instantiator.getI18NProvider().getClass());
}
@Test
public void getI18NProvider_givenDefaultI18NProvider_usePrimaryBean()
throws ServletException {
Instantiator instantiator = getInstantiator(context);
Assert.assertNotNull(instantiator.getI18NProvider());
Assert.assertEquals(PrimaryI18NTestProvider.class,
instantiator.getI18NProvider().getClass());
}
public static Instantiator getInstantiator(ApplicationContext context)
throws ServletException {
Properties properties = new Properties();
properties.put(InitParameters.I18N_PROVIDER,
DefaultI18NTestProvider.class.getName());
return SpringInstantiatorTest.getService(context, properties)
.getInstantiator();
}
}Do not rely on counting the beans of a type oneselves but instead let spring do its own resolving logic so ambiguity might actually not be an issue. If it still is fall back to the previous behavior. This fixes an issue where one might have multiple beans of an abstract or interface type in the context but has already taken care of ambiguity by hinting spring on which one to use (e.g. by using @primary, @fallback or other spring provided mechanisms). With the old implementation this would lead to an exception as it would try to instantiate a bean of an abstract type or interface, when spring would have been able to find a unique bean. This especially fixes cases where one has multiple beans of I18NProvider or MenuAccessControl which themselves are a perfect example where the old implementation was lacking. The unit tests had to be changed slightly as they use mocking and the used method on the context was changed. Fixes vaadin#18918
|
tltv
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I18NProviderInstantiationTest fails due to the new test class adding new beans being scanned by other tests too. ComponentScan need to be more specific which classes test needs. I18NProviderInstantiationTest.I18NTestConfig should have this @ComponentScan annotation:
@ComponentScan(useDefaultFilters = false, includeFilters = {
@ComponentScan.Filter(classes = { I18NTestProvider.class,
I18NTestProvider1.class }, type = FilterType.ASSIGNABLE_TYPE) })
...n-spring/src/test/java/com/vaadin/flow/spring/i18n/PrimaryI18NProviderInstantiationTest.java
Outdated
Show resolved
Hide resolved
Co-authored-by: Tomi Virtanen <tltv@vaadin.com>



This PR aims to improve the SpringInstantiator provided by the vaadin-spring module.
Do not rely on counting the beans of a type oneselves but instead let spring do its own resolving logic so ambiguity might actually not be an issue. If it still is fall back to the previous behavior.
This fixes an issue where one might have multiple beans of an abstract or interface type in the context but has already taken care of ambiguity by hinting spring on which one to use (e.g. by using
@Primary,@Fallbackor any other spring provided mechanisms, even future ones). With the old implementation this would lead to an exception as it would try to instantiate a bean of an abstract type or interface, when spring would have been able to find a unique bean if one would have let it try.This especially fixes cases where one has multiple beans of I18NProvider or MenuAccessControl but marked the bean definitions so spring knows which one to prefer.
The unit tests had to be changed slightly as they use mocking and the used method on the context was changed.
Fixes #18918