Fix the KeycloakConfigResolver for Springboot 2.6.xxx - spring-boot

***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌──->──┐
| resourceServerConfig (field private org.keycloak.adapters.KeycloakConfigResolver org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter.keycloakConfigResolver)
└──<-──┘

Add the KeycloakSpringBootConfigResolver as separate configuration outside the spring security class
#Configuration
public class KeycloakConfiguration {
#Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}

Related

Can I Autowire a Bean?

I am trying to understand Spring/Spring-boot. My question is, can I use a Bean instantiated/declaired by #Bean to a #Autowired field? Below is my classes, what i have defined.
#SpringBootApplication
public class SpringBootTestApplication {
#Bean(name = "TestServiceInterfaceImplBean")
TestServiceInterface getTestService() {
return new TestServiceInterfaceImpl();
}
#Autowired
public ServiceCaller serviceCaller;
public static void main(String[] args) {
ApplicationContext appContext = new
AnnotationConfigApplicationContext(SpringBootTestApplication.class);
Arrays.asList(appContext.getBeanDefinitionNames()).forEach(beanName ->
System.out.println(beanName));
SpringApplication.run(SpringBootTestApplication.class, args);
}
}
#Component()
public class ServiceCaller {
#Autowired
#Qualifier(value = "TestServiceInterfaceImplBean")
TestServiceInterface testService;
public ServiceCaller(){
System.out.println("############################### ServiceCaller");
}
}
//Service Interface
public interface TestServiceInterface {}
//Interface Implementation Class
public class TestServiceInterfaceImpl implements TestServiceInterface {
public TestServiceInterfaceImpl() {
System.out.println("############################### TestServiceInterfaceImpl");
}
}
I know by tagging #Service/#Component to TestServiceInterfaceImpl and removing #Bean and the method getTestService(), i can have #Autowire successful but i am just tyring to understand whether i can Autowire a Bean?
In this case i am getting below exception. By looking at the exception i am not able to understand where and how the loop is created.
Exception:
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| springBootTestApplication (field public com.SpringBootTestApplication.service.ServiceCaller com.SpringBootTestApplication.SpringBootTestApplication.serviceCaller)
↑ ↓
| serviceCaller (field com.SpringBootTestApplication.service.TestServiceInterface com.SpringBootTestApplication.service.ServiceCaller.testService)
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
You'd better move below part to a Configuration (#Configuration) class:
#Bean(name = "TestServiceInterfaceImplBean")
TestServiceInterface getTestService() {
return new TestServiceInterfaceImpl();
}
#Autowired
public ServiceCaller serviceCaller;
then do the test again. And another point, for ServiceCaller, you can even define its order after the Bean of TestServiceInterfaceImplBean created.
the 2 configuration class like:
#Configuration
#AutoConfigureAfter({ MyConfiguration2.class })
public class MyConfiguration {
public MyConfiguration() {
}
#Autowired
public ServiceCaller serviceCaller;
}
#Configuration
public class MyConfiguration2 {
public MyConfiguration2() {
}
#Bean(name = "TestServiceInterfaceImplBean")
public TestServiceInterface getTestService() {
return new TestServiceInterfaceImpl();
}
}

Spring Bean not initialized correctly

In a spring boot 2 application with spring security, I try to get local when authentication fail
#Configuration
public class AppConfig {
#Bean
public LocaleResolver localeResolver() {
I18nLocaleResolver r = new I18nLocaleResolver();
r.setDefaultLocale(Locale.ENGLISH);
return r;
}
}
In my CustomAuthenticationFailureHandler who extends SimpleUrlAuthenticationFailureHandler
I have theses attributes
#Autowired
private MessageSource messages;
#Autowired
private LocaleResolver localeResolver;
but when the onAuthenticationFailure method is called, localeResolver and mesages are null

Spring: Cannot get bean by using #Component and #Bean

I'm new in Spring framework.
I try to config 2 beans with #Bean annotation within #Component.
After that, I try to getBean (by name), I got a NoSuchBeanDefinitionException.
Please help me to resolve it.
Here is my code:
- The component:
package com.example.component;
#Component
public class FactoryMethodComponent {
private static int i;
#Bean
#Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
#Bean
#Qualifier("tb1")
public TestBean1 publicInstanceTB1() {
return new TestBean1(publicInstance());
}
}
-The xml configuration file: app-context.xml.
<beans ...>
<context:component-scan base-package="com.example.*" />
</beans>
-The test code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:app-context.xml" })
public class ComponentBeanTest {
#Test
public void test() {
System.out.println(((TestBean1)context.getBean("tb1")).getTestBean().getMethodName());
System.out.println(publicTestBean.getMethodName());
}
}
-Exception:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean
named 'tb1' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:577)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1111)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:276)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1127)
at com.example.proxy.ComponentBeanTest.test(ComponentBeanTest.java:38)
Replace #Component with #Configuration which indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
#Configuration
public class FactoryMethodComponent {
private static int i;
#Bean
#Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
#Bean
#Qualifier("tb1")
public TestBean1 publicInstanceTB1() {
return new TestBean1(publicInstance());
}
}

Spring boot mongoDB autowired null repository

I am experimenting with spring and MongoDB.
In my project I have a repository and a service which has a scheduled method.
The problem is, that the repository doesn't get autowired, it is always null.
Autowire works correctly in the main application class (tested it by implementing CommandLineRunner )
The service is found by componentScan (the constructor is called)
Am I missing somethig?
directory
MachineApplication.java
#SpringBootApplication
#EnableScheduling
public class MachineApplication {
public static void main(String[] args) {
SpringApplication.run(MachineApplication.class, args);
}
}
Worker.java
#Service
public class Worker {
#Autowired
private LineDataRepository lineDataRepository;
#Autowired
private LineRepository lineRepository;
...
public Worker() {
System.out.println("--------------------------------");
System.out.println(lineDataRepository);//null
System.out.println(lineRepository);//null
}
}
LineDataRepository
#Repository
public interface LineDataRepository extends MongoRepository<LineData, String> {
}
Add #EnableMongoRepositories to the MachineApplication to let it detect Mongo repositories.
See here
I think you haven't create mongoDbFactory and mongoTemplate bean, without this bean no connection will be made to your mongoDB. Below is the configuration:
#Configuration
public class MongoConfiguration {
#SuppressWarnings("deprecation")
#Bean
public MongoDbFactory mongoDbFactory() throws Exception {
UserCredentials userCredentials = new UserCredentials("admin", "password");
return new SimpleMongoDbFactory(new Mongo(), "myspring", userCredentials);
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}

Integrating spring-boot with RESTEasy

I am trying to prototype a Spring Boot application. I'm coming from a Guice JAX-RS application, so I prefer the standard JAX-RS annotations to Spring MVC. I've gotten Jetty up and serving:
#Configuration
#Import({ResteasyBootstrap.class, SpringBeanProcessorServletAware.class, HttpServletDispatcher.class})
public class EmbeddedJetty {
#Bean
#Singleton
public EmbeddedServletContainerFactory servletContainer() {
JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
return factory;
}
}
However, I just can't figure out how to get RESTEasy hooked up correctly. With the above SpringBeanProcessorServletAware it bails, seemingly the ServletContext is not injected through ServletContextAware before it ends up being used:
java.lang.NullPointerException: null
at org.jboss.resteasy.plugins.spring.SpringBeanProcessorServletAware.getRegistry(SpringBeanProcessorServletAware.java:30)
at org.jboss.resteasy.plugins.spring.SpringBeanProcessor.postProcessBeanFactory(SpringBeanProcessor.java:247)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:174)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:680)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:522)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
I also tried using the SpringContextLoaderListener, but that seems to conflict with the spring-boot AnnotationConfigEmbeddedWebApplicationContext class.
I'm using spring-boot 1.3.3 and spring-framework 4.3.0.rc1
The other answer won't have your resources as spring beans, this autoconfiguration will integrate them properly:
The Configuration class:
#Configuration
#ConditionalOnWebApplication
public class RestEasyAutoConfigurer {
private Environment environment;
#Bean(name = "resteasyDispatcher")
public ServletRegistrationBean resteasyServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HttpServletDispatcher(), getPrefix()
+ "/*");
registrationBean.setInitParameters(ImmutableMap.of("resteasy.servlet.mapping.prefix", "/rs/")); // set prefix here
registrationBean.setLoadOnStartup(1);
return registrationBean;
}
#Bean(destroyMethod = "cleanup")
public static RestEasySpringInitializer restEasySpringInitializer() {
return new RestEasySpringInitializer();
}
#Bean
// use Spring Boot configured Jackson
public CustomResteasyJackson2Provider jackson2Provider(ObjectMapper mapper) {
return new CustomResteasyJackson2Provider(mapper);
}
public static class RestEasySpringInitializer
implements
ServletContextInitializer,
ApplicationContextAware,
BeanFactoryPostProcessor {
private ResteasyDeployment deployment;
private ConfigurableApplicationContext applicationContext;
private ConfigurableListableBeanFactory beanFactory;
public void cleanup() {
deployment.stop();
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
ListenerBootstrap config = new ListenerBootstrap(servletContext);
deployment = config.createDeployment();
deployment.start();
servletContext.setAttribute(ResteasyProviderFactory.class.getName(), deployment.getProviderFactory());
servletContext.setAttribute(Dispatcher.class.getName(), deployment.getDispatcher());
servletContext.setAttribute(Registry.class.getName(), deployment.getRegistry());
SpringBeanProcessor processor = new SpringBeanProcessor(deployment.getDispatcher(),
deployment.getRegistry(), deployment.getProviderFactory());
processor.postProcessBeanFactory(beanFactory);
applicationContext.addApplicationListener(processor);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
}
}
And the Jackson provider:
#Provider
#Consumes({"application/*+json", "text/json"})
#Produces({"application/*+json", "text/json"})
public class CustomResteasyJackson2Provider extends ResteasyJackson2Provider {
private ObjectMapper mapper;
public CustomResteasyJackson2Provider(ObjectMapper mapper) {
this.mapper = mapper;
}
#Override
public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) {
return Optional.ofNullable(_mapperConfig.getConfiguredMapper()).orElse(mapper);
}
}
NOTE: this is a working configuration for Spring Boot 1.3.3 / RESTEasy 3.0.16
You can use RESTEasy Spring Boot starter. Here is how you do it:
Adding POM dependency
Add the Maven dependency below to your Spring Boot application pom file.
<dependency>
<groupId>com.paypal.springboot</groupId>
<artifactId>resteasy-spring-boot-starter</artifactId>
<version>2.1.1-RELEASE</version>
<scope>runtime</scope>
</dependency>
Registering JAX-RS application classes
Just define your JAX-RS application class (a subclass of Application) as a Spring bean, and it will be automatically registered. See the example below. See section JAX-RS application registration methods in How to use RESTEasy Spring Boot Starter for further information.
package com.test;
import org.springframework.stereotype.Component;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#Component
#ApplicationPath("/sample-app/")
public class JaxrsApplication extends Application {
}
Registering JAX-RS resources and providers
Just define them as Spring beans, and they will be automatically registered. Notice that JAX-RS resources can be singleton or request scoped, while JAX-RS providers must be singletons.
Further information at the project GitHub page.
Here is fully working example.
First, a sample JAX-RS endpoint:
#Path("/api")
public class SampleResource {
#GET
#Path("/sample")
#Produces(MediaType.APPLICATION_JSON)
public String getSample() {
return "Some JSON";
}
}
Next, a JAX-RS configuration class that loads all endpoints.
import javax.ws.rs.core.Application;
public class RestEasyConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(SampleRest.class);
return classes;
}
}
Finally, in your Spring configuration, initialize RESTEast filter and inform the framework about its existence.
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.jboss.resteasy.plugins.server.servlet.FilterDispatcher;
...
#Bean
public FilterRegistrationBean filterRegistrationBean() {
Map<String, String> initParams = new HashMap<>();
initParams.put("javax.ws.rs.Application", RestEasyConfig.class.getCanonicalName());
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new FilterDispatcher());
registrationBean.setInitParameters(initParams);
return registrationBean;
}
Your endpoint should be up and running. If you are missing the FilterDispatcher class on your class path, add the resteasy-jaxrs library to your build descriptor.

Resources