Turn POJO to #Configuration programmatically Spring - java

Given a class:
class MyConfiguration {
#Bean
String bean() {
return new String();
}
}
as you may notice it does not have #Configuration annotation.
How can I make it behave like it has #Configuration annotation, but not adding it?
#Bean annotation should not work in Lite Mode, https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html
Something like:
#Configuration
class MainConfiguration {
#Bean
MyConfiguration myConfiguration() {
MyConfiguration myConfiguration = do_some_spring_magic();
// myConfiguration behaving like it's having #Configuration here
return myConfiguration;
}
}

I dont understand what is the use case you are trying to achieve here.. But if you are looking for programatically registering beans into the Spring Context then you can do it as below.
#Configuration
public class MyBeanRegisterFactory implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
//depending on some condition you can do the below line
beanRegistry.registerBeanDefinition("myBeanClass", new RootBeanDefinition("com.mybean.MyBeanClass"));
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
In Your case, the bean definitions inside the class MyConfiguration can be programatically registered as below into to the spring context.
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/support/BeanDefinitionRegistryPostProcessor.html

Related

How to inject pojo class in spring?

I have a pojo class which i need to inject in component. how to inject pojo object in spring?
For example
RestClass is under Module(like one microservice). Pojo Value should be injected here only. service class and pojo is different module.
#Controller
public class RestClass {
#Autowired
private ServiceClass serviceClass;
// How to apply MyConfig pojo object into ServiceClass
//like MyConfig.Builder().limit(100).build();
#PostMapping("/business")
private void callDoBusiness(){
serviceClass.doBusiness();
}
}
//// ServiceClass and Pojo class is under one module. Pojo object should not construct here. should be passed from another module
#Service
public class ServiceClass {
#Autowired
private MyConfig myConfig;
public void doBusiness(){
System.out.println(myConfig.getLimit())
}
}
#Builder
#Getter
public class MyConfig {
private int limit;
.
.
}
#Bean annotation is used in your case. For example:
Create some configuration file with #Configuration annotation. It doesn't matter where you create your Config configuration class or how you name it. You can even have multiple #Configuration classes across your project.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
class Config {
// configure your MyConfig class here as a bean
#Bean
public MyConfig myConfig() {
return MyConfig.Builder().limit(100).build();
}
}
Now you can autowire it wherever you use it as in you example.
You can use #Configuration and #Bean. Something like this
AppConfig.java
#Configuration
public class AppConfig {
#Bean
public PojoClass getBean(){ return new PojoClass();}
}
You can use #Bean
#Configuration
public class Config {
#Bean
public MyConfig MyConfig() {
return new MyConfig();
}
}

how to load #Configuration classes in an order in spring boot

i would like to load #Configuration classes in an order. i have two configuration classes. i am having a requirement of loading my SampleProperties class before sampleconfiguration class.
I have tried the following annotations but it is not working as expected.
#AutoConfigureAfter(SampleProperties.class )
#AutoConfigureBefore(SampleConfiguration.class)
I have put my congiurations class in diff package in order to read configurations classes in an order.using #Import function, i am including my configuration classes into my application
My Main Class:
#Import({SampleProperties.class,SampleConfiguration.class,})
public class SampleApplication{
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
My SampleProperties Class
#Configuration
#AutoConfigureBefore(SampleConfiguration.class)
#ConfigurationProperties("demo")
#Data
public class SampleProperties {
private String team;
private int teamSize;
private String teamLeader;
}
My sampleconfiguration Class:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef="sampleEntityManager",
transactionManagerRef="sampleTransactionManager",
basePackages= {"com.example.demo.repo"})
#AutoConfigureAfter(SampleProperties.class)
public class SampleConfiguration {
#Autowired
Environment env;
#Bean(name="sampleDataSource")
#Primary
public DataSource dmsDataSource() {
// functions
return null;
}
#Primary
#Bean(name = "sampleEntityManager")
public LocalContainerEntityManagerFactoryBean dmsEntityManagerFactory(EntityManagerFactoryBuilder builder) {
// functions
return null;
}
#Primary
#Bean(name = "sampleTransactionManager")
public PlatformTransactionManager dmsTransactionManager(#Qualifier("sampleEntityManager") EntityManagerFactory entityManagerFactory) {
// functions
return null;
}
}
can anyone tell me what missing and where am making mistakes?
I think you have to use #Order annotation.
#Component
#Order(1)
public class SampleProperties {
// code
}
#Component
#Order(2)
public class SampleConfiguration {
// code
}

#autowired annotation for service class is not working in #configure class spring boot

when i am using #autowire to inject my dependencies in Configuration
class its giving me as null please refer the code below .
#Configuration
public class DataSourceConfig {
#Autowired
AppService appService;
#Bean
public BeanDefinitionRegistryPostProcessor beanPostProcessor() {
return new BeanDefinitionRegistryPostProcessor() {
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0) throws BeansException {
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanRegistry) throws BeansException {
createBeans(beanRegistry);
}
};
}
private void createBeans(BeanDefinitionRegistry beanRegistry,DataSourceConfigService ds) {
appService.getDbDetails();
appService is null here if i will call it using this way
BeanDefinitionRegistryPostProcessor beanPostProcessor(AppService
appService) then in AppServiceImpl class AppDao dependency will be null
}
}
//// Service
#Service
public class AppServiceImpl implements AppService{
#Autowired
AppDao ds;
#Override
public List<A> getDatabaseConfiguration() {
return ds.getDbDetails(); // here ds is null
}
}
//dao
#Repository
public class AppDaoImpl implements AppDao {
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
#Override
public List<A> getDbDetails() {
return nameParamJdbcTemplate.query(SELECT_QUERY, new DataSourceMapper()); // nameParamJdbcTemplate is null
}
// datasource config
#Configuration
public class DataSourceBuilderConfig {
#Bean(name = "dbSource")
#ConfigurationProperties(prefix = "datasource")
#Primary
public DataSource dataSource1() {
return DataSourceBuilder.create().build();
}
#Bean(name = "nameParamJdbcTemplate")
#DependsOn("dbSource")
#Autowired
public NamedParameterJdbcTemplate jdbcTemplate1(#Qualifier("dbSource") DataSource dbSource) {
return new NamedParameterJdbcTemplate(dbSource);
}
}
What i want is when ever my beanPostProcessor()
is executed i want all my dependent beans should be instantiated ie
#Autowired
AppService appService;
#Autowired
AppDao ds;
#Qualifier("nameParamJdbcTemplate")
#Autowired
public NamedParameterJdbcTemplate nameParamJdbcTemplate;
I am new to spring so any help or working examples would be great. Thanks
It is null because this #Configuration class also defines a BeanDefinitionRegistryPostProcessor that forces the context to create that bean very early on.
Because you are using field injection, the context has to resolve AppService bean but it can't yet because the post-processor have to be applied first.
Your configuration looks very complex so you may want to simplify it a bit:
Separate low-level infrastructure configuration from main configuration
Always define such post processor as public static method so that the context can invoke the #Bean method without having to construct the class first.

Spring addFormatters not called of WebMvcConfigurerAdapter

I'm trying to implement a converter in a Spring Boot app but for some reason my override of addFormatters(FormatterRegistry formatterRegistry) is never called. What's confusing is that other overridden methods are called, addInterceptors works just fine. Security is enabled for this app.
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"com.company.web"})
public class WebMvcConfig extends WebMvcConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
#Inject
private TenantIdentifierInterceptorAdapter multiTenancyInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
logger.info("adding interceptor");
registry.addInterceptor(multiTenancyInterceptor);
}
//THIS IS NOT CALLED
#Override
public void addFormatters(FormatterRegistry formatterRegistry) {
logger.info("adding converters");
formatterRegistry.addConverter(new StringToPersonConverter());
}
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {"classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/"};
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS)
.setCachePeriod(3600).resourceChain(true).addResolver(new PathResourceResolver());
}
#PostConstruct
public void init() {
requestMappingHandlerAdapter.setIgnoreDefaultModelOnRedirect(true);
}
}
For some reason if I add this code to the file the formatter code is hit, but I get an error "A ServletContext is required to configure default servlet handling" and the app won't compile.
#Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
Have you configured a bean with super class WebMvcConfigurationSupport?
If you did so, it will disable WebMvcAutoConfiguration Bootstrap.
Check this code:
#Configuration
#ConditionalOnWebApplication(
type = Type.SERVLET
)
#ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
#ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
#AutoConfigureOrder(-2147483638)
#AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
I'm not 100% sure but did you try to remove #EnableWebMvc annotation from the class? Because according to documentation it shouldn't be there:
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own #Configuration class of type WebMvcConfigurerAdapter, but without #EnableWebMvc.
M. Deinum's comment was the answer. I've removed #EnableWebMvc and removed the method addFormatters, then added:
#Bean
StringToPersonConverter stringToPersonConverter() {
return new StringToPersonConverter();
}
I have solved a similar error
EnableWebMvc
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Documented
#Import(DelegatingWebMvcConfiguration.class)
public #interface EnableWebMvc {
}
DelegatingWebMvcConfiguration
#Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
#Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
//...
#Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
//...
}
WebMvcConfigurationSupport
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
//...
#Bean
public FormattingConversionService mvcConversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
addFormatters(conversionService);
return conversionService;
}
/**
* Override this method to add custom {#link Converter}s and {#link Formatter}s.
*/
protected void addFormatters(FormatterRegistry registry) {
}
//...
}
My custom config with multiple WebMvcConfigurerAdapter implements WebMvcConfigurer
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter
{
#Autowired
private ConversionService conversionService;
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers)
{
argumentResolvers.add(new RequestTenantResolverComposite(conversionService));
}
}
The method will not be called if the FormattingConversionService implements ConversionService bean created before WebMvcConfigurer injected.
I solved my question using Lazy annotion for ConversionService with spring verions 4.3.6.

How to optionally import a Spring managed component?

I have created a custom API jar library where I'd like to provide some commonly used services.
But I'd like to use and autowire some of these services optionally in my implementation projects. They should not get autowired automatically.
How could I tell Spring explicit to include the following StatsLogger?
API jar:
package my.spring.config
//#Component
public class MyStatsLogger {
#Autowired
private MyService someOtherServiceForLogging;
#Scheduled(fixedDelay = 60000)
public void log() {
//logging
}
}
IMPL project:
#Configuration
#EnableScheduling
public class AppConfig {
}
Simply add the service to your context:
#Configuration
#EnableScheduling
public class AppConfig {
#Bean
public MyStatsLogger myStatsLogger() {
return new MyStatsLogger();
}
}
Since MyStatsLogger has a default constructor, all you need to is the following:
#Configuration
#EnableScheduling
public class AppConfig {
#Bean
public MyStatsLogger myStatsLogger() {
return new MyStatsLogger();
}
}
The MyService dependency in MyStatsLogger will automatically be wired by Spring if of course there is a bean of type MyService declared.

Categories

Resources