Spring Boot application is ignoring java config - spring-boot

I have a fairly simple Spring Boot app I am working on that uses a few Java Config classes. However, it seems that the configuration is not being picked up. I have break points all over, but nothing gets tripped. I even tossed a few RuntimeExceptions just to see if maybe my debugger was on the fritz.
In my main class, I have the standard Spring Boot main:
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
As you can see, I tagged it with #ComponentScan and #EnableAutoConfiguration. The Application class lives at the root of the classpath. My understanding of the #ComponentScan annotation is that it will search for all configuration classes beneath it.
In a package one layer down I have all the config classes:
My "Common" configuration
#Configuration
#EnableJpaRepositories("com.codechimp.XXX.repository")
#EnableTransactionManagement
public class AppCommonConfig {
#Inject
private Environment environment;
/* Define common beans here like datasource and such */
}
And my Spring Security configuration
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Inject
private LocalXXXUserDetailsService localXXXUserDetailsService;
/**
* #see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(HttpSecurity)
*/
#Autowired
protected void configure(HttpSecurity http) throws Exception {
// Configure http
}
/**
* #see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configureGlobal(AuthenticationManagerBuilder)
*/
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
// Configure auth
}
}
However, when I run the app, it doesn't seem to call any of the methods in either of these config classes. It's as if they are being completely ignored. As I said, I have tried setting break points and even throwing a RuntimeException right in the beginning of all the methods like so:
if (true)
throw new RuntimeException("Break!");
Admittedly I have not had much experience with using Java Config, but I have been over the docs again and again and I am not seeing the missing piece(s).

I think you need your Application to be a #Configuration.
It's not a great idea to do a #ComponentScan from the default package (I assume that's what you mean by "the root of the classpath"). That would definitely switch some things off, but more seriously it causes a huge scan of all jars on your classpath, which is not a great idea (and can cause the app to fail).

You need to add
#SpringBootApplication
to your Spring Boot main class. From the docs:
/**
* Indicates a {#link Configuration configuration} class that declares one or more
* {#link Bean #Bean} methods and also triggers {#link EnableAutoConfiguration
* auto-configuration} and {#link ComponentScan component scanning}. This is a convenience
* annotation that is equivalent to declaring {#code #Configuration},
* {#code #EnableAutoConfiguration} and {#code #ComponentScan}.
*
* #author Phillip Webb
* #author Stephane Nicoll
* #since 1.2.0
*/

Related

When to use #EnableHypermediaSupport?

According to the Spring HATEOAS API,
Activates hypermedia support in the ApplicationContext. Will register infrastructure beans to support all appropriate web stacks based on selected HypermediaMappingInformation-type as well as the classpath.
My Spring Boot application (2.3.4) has the following dependencies:
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
My SpringBootApplication class:
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// run this application as a Spring application
SpringApplication.run(MyApplication.class, args);
}
}
I've noticed my repositories are returning HALresponses via Spring Data REST without annotating my application class with #EnableHypermediSupport. When is this annotation needed? Do I not need it since I'm using Spring Data REST?
Spring Boot already auto configures for you if your dependencies contains spring-hateoas. The dependency spring-boot-starter-data-rest contains spring-hateoas.
File org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration has #EnableHypermediaSupport(type = HypermediaType.HAL).
/**
* {#link EnableAutoConfiguration Auto-configuration} for Spring HATEOAS's
* {#link EnableHypermediaSupport #EnableHypermediaSupport}.
*
* #author Roy Clarkson
* #author Oliver Gierke
* #author Andy Wilkinson
* #since 1.1.0
*/
#Configuration(proxyBeanMethods = false)
#ConditionalOnClass({ EntityModel.class, RequestMapping.class, RequestMappingHandlerAdapter.class, Plugin.class })
#ConditionalOnWebApplication
#AutoConfigureAfter({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, RepositoryRestMvcAutoConfiguration.class })
#EnableConfigurationProperties(HateoasProperties.class)
#Import(HypermediaHttpMessageConverterConfiguration.class)
public class HypermediaAutoConfiguration {
#Configuration(proxyBeanMethods = false)
#ConditionalOnMissingBean(LinkDiscoverers.class)
#ConditionalOnClass(ObjectMapper.class)
#EnableHypermediaSupport(type = HypermediaType.HAL)
protected static class HypermediaConfiguration {
}
}
Of course, you can override the default configuration.
#Configuration
#EnableHypermediaSupport(…)
class MyHypermediaConfiguration { … }

Migration to Spring Boot (Security) 2 from 1.x

In a current migration of a project from Spring boot 1.X to 2.0.9 I am facing a hard time with the Spring Security module. In a first step I have to change the properties to access the datasources (to jdbc-url) and now that part seems to be working just fine, but now the security module seems to be not rightly attached.
So in properties I have tried to add the following:
spring.security.user.name=admin
spring.security.user.password=secret
But even if I comment it or dis-comment it, I face the same result, when I call the webservices, the dialog prompts asking for credentials:
The configuration of the authentication is the following:
class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
#Configuration
#EnableAuthorizationServer // [1]
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Autowired
private DataSource oauthDataSource;
#Autowired
private PhrqlAuthenticationManager phrqlAuthenticationManager;
/**
* Config clientDetail storage
* #param endpoints
* #throws Exception
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(phrqlAuthenticationManager);
endpoints.tokenStore(tokenStore);
// endpoints.tokenStore(tokenStore).pathMapping("/oauth/token", "/p/oauth/token");
}
#Override // [3]
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(oauthDataSource);
}
}
For some reason, I think that the autoconfig is not accessing to the name-pass, so then the client ask for credentials. Any help will be much appreciated. Thanks in advance!

No further requests expected while MockRestServiceServer was set to ExpectedCount.manyTimes()

I have following test class for my spring-integration application that passes sucessfully being launched alone
#SpringBootTest(classes = {BackupTestDefinition.class})
#ActiveProfiles({"test", "dev"})
#RunWith(SpringRunner.class)
public class BackupServiceTest {
#Value(value = "${ne.endpoint}")
private String ne;
#Autowired
private RestTemplate restTemplate;
private MockRestServiceServer mockServer;
#Before
public void setup() {
mockServer = MockRestServiceServer.bindTo(restTemplate).build(new UnorderedRequestExpectationManager());
mockServer.expect(ExpectedCount.manyTimes(), requestTo(UriComponentsBuilder.fromHttpUrl(ne).build().toUri())).andExpect(method(HttpMethod.POST)).andRespond(withSuccess());
}
#Test
public void testNotificationProcessing() throws IOException, InterruptedException, InitializationException, ExecutionException {
//some testing code
}
}
But I have another test that has other settings (ExpectedCount.times(1)) for the same endpoint and has different TestDefinition. So there are couple of contexts cached in this test suite. And when I launch them together I receive following exception
at org.springframework.test.web.client.AbstractRequestExpectationManager.createUnexpectedRequestError(AbstractRequestExpectationManager.java:141)
at org.springframework.test.web.client.UnorderedRequestExpectationManager.validateRequestInternal(UnorderedRequestExpectationManager.java:49)
at org.springframework.test.web.client.AbstractRequestExpectationManager.validateRequest(AbstractRequestExpectationManager.java:76)
at org.springframework.test.web.client.MockRestServiceServer$MockClientHttpRequestFactory$1.executeInternal(MockRestServiceServer.java:289)
at org.springframework.mock.http.client.MockClientHttpRequest.execute(MockClientHttpRequest.java:94)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:659)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:620)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:538)
Caused by: java.lang.AssertionError: No further requests expected: HTTP POST
After hours of debugging I found out that settings were successfully applied, but looks like restTemplate was called from another context where number of attempts was exhausted. Can you please help me to find out how this issue can be resolved.
This issue can be resolved using #DirtiesContext on the test class, alongside with the #RunWith:
* Test annotation which indicates that the
* {#link org.springframework.context.ApplicationContext ApplicationContext}
* associated with a test is <em>dirty</em> and should therefore be closed
* and removed from the context cache.
*
* <p>Use this annotation if a test has modified the context — for
* example, by modifying the state of a singleton bean, modifying the state
* of an embedded database, etc. Subsequent tests that request the same
* context will be supplied a new context.
*
* <p>{#code #DirtiesContext} may be used as a class-level and method-level
* annotation within the same class or class hierarchy. In such scenarios, the
* {#code ApplicationContext} will be marked as <em>dirty</em> before or
* after any such annotated method as well as before or after the current test
* class, depending on the configured {#link #methodMode} and {#link #classMode}.
*
And here are Docs on the matter: https://docs.spring.io/spring/docs/5.0.6.RELEASE/spring-framework-reference/testing.html#dirtiescontext

Configuring Spring to ignore dependencies annotated with #Inject

I have an EJB class in which I need to inject two beans - one should be injected by the EJB container and other is a Spring Container.
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
#LocalBean
public class SomeClass {
#Inject
private EJBClass a;
#Autowired
private SpringComponent b;
}
Here, the Spring interceptor trying to intercept the injection of bean 'a' and it's getting failed. I want the EJB container to inject the bean 'a' and Spring container to inject bean 'b'.
Please show me a way out here.
By customizing the SpringBeanAutowiringInterceptor class, dependencies annotated with #Inject can be excluded from auto wiring.
To understand what happens behind the scene, have a look at source code of
SpringBeanAutowiringInterceptor.java -
/**
* Actually autowire the target bean after construction/passivation.
* #param target the target bean to autowire
*/
protected void doAutowireBean(Object target) {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
configureBeanPostProcessor(bpp, target);
bpp.setBeanFactory(getBeanFactory(target));
bpp.processInjection(target);
}
At first line, of doAutowireBean, a new instance of AutowiredAnnotationBeanPostProcessor is created. Here set of annotations to be scanned for auto wiring dependencies are configured.
/**
* Create a new AutowiredAnnotationBeanPostProcessor
* for Spring's standard {#link Autowired} annotation.
* <p>Also supports JSR-330's {#link javax.inject.Inject} annotation, if available.
*/
#SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
Since, by default, the #Inject annotation is configured spring scans respective dependencies marked with #Inject and tries to auto wire them.
To exclude #Inject annotated dependencies write below custom class.
public class CustomSpringBeanAutowiringInterceptor extends SpringBeanAutowiringInterceptor {
/**
* Template method for configuring the
* {#link AutowiredAnnotationBeanPostProcessor} used for autowiring.
* #param processor the AutowiredAnnotationBeanPostProcessor to configure
* #param target the target bean to autowire with this processor
*/
protected void configureBeanPostProcessor(AutowiredAnnotationBeanPostProcessor processor, Object target) {
Set<Class> annotationsToScan = new HashSet<Class>();
annotationsToScan.add(Autowired.class);
annotationsToScan.add(Value.class);
processor.setAutowiredAnnotationTypes(annotationsToScan);
}
}
Here configureBeanPostProcessor hook is utilized to customize the bean post processor so as to include only those annotations which we require to be auto wired.
After applying this custom class as interceptor in code the desired behaviour can be achieved
#Stateless
#Interceptors(CustomSpringBeanAutowiringInterceptor.class)
#LocalBean
public class SomeClass {
#Inject
private EJBClass a;
#Autowired
private SpringComponent b;
}
Let know in comments if you face any issues. Also feel free to optimize the code as deemed fit and excuse any compilations / formatting issues.
Use #EJB annotation to inject EJB

How to implement ServletContextListener in struts2, spring, hibernate application?

In my application I want to store some of my data in ServletContext as its going to be used through out the application. Data are saved in a database. All the configurations are made through integrating struts2, spring, hibernate. Problem is that, I am finding difficulties to fetch the data from the database. Spring is unable to inject the dao impl class to the class that is implementing the ServleltContextListener. Can anyone please tell me how to do this? Or is there any alternative?
Try this
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class MyListener implements ServletContextListener
{
/**
* #see javax.servlet.ServletContextListener#contextInitialized
* (javax.servlet.ServletContextEvent)
*/
#Override
public void contextInitialized(ServletContextEvent sce)
{
WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
Object yourDaoImplClass = applicationContext.getBean("your_bean_name_or_bean_id");
//You can type cast yourDaoImplClass to your object
}
/**
* #see javax.servlet.ServletContextListener#contextDestroyed
* (javax.servlet.ServletContextEvent)
*/
#Override
public void contextDestroyed(ServletContextEvent sce)
{
}
}
Hope this works. Let me know how it goes.
The best approach would be to implement Spring's ServletContextAware interface and then use an #PostConstruct or afterPropertiesSet method to add items to the servlet context.

Resources