embedded tomcat valve spring boot - spring-boot

I'm trying to configure the LogbackValve for getting access logs in case my Spring Boot based web application is running from embedded Tomcat. Following is the code for configuration:
import javax.servlet.Servlet;
import org.apache.catalina.startup.Tomcat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ch.qos.logback.access.tomcat.LogbackValve;
#Configuration
public class EmbeddedTomcatConfigurator {
#Bean
#ConditionalOnClass({ Servlet.class, Tomcat.class })
#ConditionalOnBean(value = LogbackValve.class)
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(LogbackValve logbackValve) {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addContextValves(logbackValve);
return factory;
}
#Bean
#ConditionalOnProperty(name = "embedded.tomcat.logback.access.config.path")
public LogbackValve logbackValve(#Value("${embedded.tomcat.logback.access.config.path:}") String fileName) {
LogbackValve logbackValve = new LogbackValve();
logbackValve.setFilename(fileName);
return logbackValve;
}
}
However, everytime I start the application using "mvn spring-boot:run" in debug mode, I see logs saying, "LogbackValve not found" when trying to create instance of "tomcatEmbeddedServletContainerFactory" bean. However, another log statement indicates creation of this bean. Due to this, it always initializes the bean defined in the auto-configuration class "org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration".
For now, I've modified my class as :
import javax.servlet.Servlet;
import org.apache.catalina.startup.Tomcat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ch.qos.logback.access.tomcat.LogbackValve;
#Configuration
public class EmbeddedTomcatConfigurator {
#Bean
#ConditionalOnClass({ Servlet.class, Tomcat.class })
#ConditionalOnProperty(name = "embedded.tomcat.logback.access.config.path")
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(#Value("${embedded.tomcat.logback.access.config.path:}") String logbackAccessPath) {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.addContextValves(getLogbackValve(logbackAccessPath));
return factory;
}
private LogbackValve getLogbackValve(String fileName) {
LogbackValve logbackValve = new LogbackValve();
logbackValve.setFilename(fileName);
return logbackValve;
}
}
I've already asked this question on Git and it has been resolved. But, here, the point I'm trying to bring up is, why the #ConditionalOnBean(value = LogbackValve.class) isn't detecting the bean, which has been defined as well.

Related

Parameter 1 of constructor in required a bean of type that could not be found

I've been stuck for a while now. I'm modifying my Spring Security project by adding Jwt. Currently, I'm trying to make the JwtEncoder and JwtDecoder work in SecurityConfig, I need RSAPrivateKey and RSAPublicKey for these methods. To get these Key-values I'm using a Record with #ConfigurationProperties annotation. But Getting this Record into the SecurtyConfig gives me some problems:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of constructor in com.ssl.app.security.config.SecurityConfig required a bean of type 'com.ssl.app.security.config.RsaKeyProperties' that could not be found.
Action:
Consider defining a bean of type 'com.ssl.app.security.config.RsaKeyProperties' in your configuration.
This is my SecurtyConfig
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import com.ssl.app.security.filters.LoginAuthFilter;
import com.ssl.app.utility.ConsoleUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
//#AllArgsConstructor
#EnableWebSecurity
//#EnableConfigurationProperties
public class SecurityConfig {
private final LoginAuthFilter loginAuthFilter;
private final RsaKeyProperties rsaKeyProperties;
public SecurityConfig(LoginAuthFilter loginAuthFilter, RsaKeyProperties rsaKeyProperties) {
this.loginAuthFilter = loginAuthFilter;
this.rsaKeyProperties = rsaKeyProperties;
}
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeRequests(auth -> auth
.anyRequest().authenticated()
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) // get config_class :: method
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(loginAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
#Bean
JwtDecoder jwtDecoder() {
ConsoleUtil.PrintRow(this.getClass().getSimpleName(),"Decode publicKey", "true");
// Get public key and decode and return
return NimbusJwtDecoder.withPublicKey(rsaKeyProperties.publicKey()).build();
}
#Bean
JwtEncoder jwtEncoder() {
ConsoleUtil.PrintRow(this.getClass().getSimpleName(),"Encode jwt", true);
JWK jwk = new RSAKey.Builder(rsaKeyProperties.publicKey()).privateKey(rsaKeyProperties.privateKey()).build();
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}
}
Record
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
#ConfigurationProperties(prefix ="rsa")
public record RsaKeyProperties(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
}
I tried adding #EnableConfigurationProperties, and EnableAutoConfiguration to the SecurtyConfig would work, but it has no effect. #Value annotation don't work either. The SecurityConfig required a bean, but what bean?
Maybe you should refer to this article
spring-security-jwt

Spring Boot & Hibernate Validation's ConstraintMappingContributor

The hibernate validations documentation describes how to create ConstraintMappingContributors here.
It states:
You then need to specify the fully-qualified class name of the
contributor implementation in META-INF/validation.xml, using the
property key hibernate.validator.constraint_mapping_contributors. You
can specify several contributors by separating them with a comma.
Given I have many of these, what would be the most appropriate way to auto-discover these i.e. via #Component and add them dynamically at runtime to the ConstrainMappingConfiguration during Spring Boot startup.
For example.. if a developer creates a new ConstraintMappingContributor, it should be picked up and added automatically when spring boot starts, requiring no other file changes.
This is what I came up with, seems to be working for me.
package...
import org.hibernate.validator.spi.cfg.ConstraintMappingContributor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
#Configuration
public class ValidationConfiguration {
private final List<ConstraintMappingContributor> contributors;
public ValidationConfiguration(Optional<List<ConstraintMappingContributor>> contributors) {
this.contributors = contributors.orElseGet(ArrayList::new);
}
#Bean
public LocalValidatorFactoryBean validatorFactory() {
return new ValidatorFactoryBean(this.contributors);
}
}
package...
import org.hibernate.validator.HibernateValidatorConfiguration;
import org.hibernate.validator.internal.cfg.context.DefaultConstraintMapping;
import org.hibernate.validator.spi.cfg.ConstraintMappingContributor;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import javax.validation.Configuration;
import java.util.List;
public class ValidatorFactoryBean extends LocalValidatorFactoryBean {
private final List<ConstraintMappingContributor> contributors;
ValidatorFactoryBean(List<ConstraintMappingContributor> contributors) {
this.contributors = contributors;
}
#Override
protected void postProcessConfiguration(Configuration<?> cfg) {
if (cfg instanceof HibernateValidatorConfiguration) {
HibernateValidatorConfiguration configuration = (HibernateValidatorConfiguration) cfg;
this.contributors.forEach(contributor -> contributor.createConstraintMappings(() -> {
DefaultConstraintMapping mapping = new DefaultConstraintMapping();
configuration.addMapping(mapping);
return mapping;
}));
}
}
}
I invoke it like this...
if(SpringValidatorAdapter.class.isInstance(this.validatorFactory)){
SpringValidatorAdapter.class.cast(this.validatorFactory).validate(entity, errors);
}

Configuring MessageTransformer for ActiveMQ/Stomp in SpringBoot

I have a springboot project with ActiveMQ and Stomp.
I want every Message sent or received to run through a MessageTransformer, to do specific serialization/deserialization stuff.
The Stomp Message exchange with my WebApp works, but the installed MessageTransformer is never called.
Does anybody have an idea what could be wrong? Thank you much!
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.MessageTransformer;
import org.apache.activemq.broker.BrokerFactory;
import org.apache.activemq.broker.BrokerService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Value("${stomp.port}") // 61616
int stompPort;
#Bean
public ActiveMQConnectionFactory activeMQConnectionFactory() {
ActiveMQConnectionFactory activeMQConnectionFactory =
new ActiveMQConnectionFactory("vm://localhost");
// Install Message Converter ## But does not work ##
MessageTransformer messageTransformer = new ClientMessageTransformer();
activeMQConnectionFactory.setTransformer(messageTransformer);
return activeMQConnectionFactory;
}
#Bean
public BrokerService brokerService() throws Exception {
BrokerService brokerService =
BrokerFactory.createBroker(String.format(
"broker:(stomp://localhost:%d)" +
"?persistent=false&useJmx=false&useShutdownHook=true",
stompPort));
return brokerService;
}

Spring find 2 candidates, but there is only one

I'm trying upgrade a JHipster project, however I found the following issue:
Description:
Parameter 0 of constructor in com.cervaki.config.AsyncConfiguration required a single bean, but 2 were found:
- jhipster-io.github.jhipster.config.JHipsterProperties: defined in null
- io.github.jhipster.config.JHipsterProperties: defined in null
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
What I understood is that spring can't inject the correct bean because there are two candidates, but I only have the io.github.jhipster.config.JHipsterProperties implementation:
package com.cervaki.config;
import io.github.jhipster.async.ExceptionHandlingAsyncTaskExecutor;
import io.github.jhipster.config.JHipsterProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.*;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
#Configuration
#EnableAsync
#EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
private final JHipsterProperties jHipsterProperties;
public AsyncConfiguration(JHipsterProperties jHipsterProperties) {
this.jHipsterProperties = jHipsterProperties;
}
#Override
#Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize());
executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize());
executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity());
executor.setThreadNamePrefix("cervaki-Executor-");
return new ExceptionHandlingAsyncTaskExecutor(executor);
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
You can download the pom.xml here.
I did a search in the entire code and libs to find the jhipster-io.github.jhipster.config.JHipsterProperties file, however I didn't find anything.
What can I do to solve this problem?
I also faced this issue after generating new JhipsterApp,
And as you - I don't find the "jhipster-io" dependencies in project
How I solve this:
in src/main/java/your/package/config create a "AppConfiguration.java"
with content:
import io.github.jhipster.config.JHipsterProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
#Configuration
public class AppConfiguration {
#Bean
#Primary
public JHipsterProperties jHipsterProperties() {
return new JHipsterProperties();
}
}
even without #Primary - I haven't got this error

spring boot #Value always null

I am using spring boot 1.5.3 and trying to inject the properties from an application-dev.properties file into a Service bean but the value is always coming as null. The value does get loaded in my DevConfiguration class though.
I have a application class as below in my base package
package com.me;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I have a configuration class as follows in
package com.me.print.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
#Configuration
#Profile("dev")
#PropertySources({
#PropertySource("classpath:application.properties"),
#PropertySource("classpath:application-dev.properties")
})
#ComponentScan(value = {"com.me.print.client"})
public class DevConfiguration {
#Value("${app.service.url}")
private String rootUri;
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
My Service bean that I am trying to load the value into is below
package com.me.print.client;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.me.print.model.zitResponse;
#Service
public class zitPrintClient {
private final RestTemplate restTemplate;
#Value("${app.service.url}")
private String rootUri;
public zitPrintClient(RestTemplateBuilder restTemplateBuilder) {
restTemplate = restTemplateBuilder
//.rootUri(rootUri)
.build();
}
public zitResponse getpooltatus(String poolId) {
return restTemplate.getForObject("/pool/{poolId}/#status",
zitResponse.class, poolId);
}
}
In the above class the rootURI is always null. Does anyone have any suggestions as to what I am missing
in my application-dev.properties file I have the following
app.service.url=http://localhost:8080/zitprint/v1
Thanks
UPDATE:
does anyone have any suggestions here as I tried to inject properties into my controller as follows:
#Value("${allowedVendors}") String allowedVendors
and if i put the above into a constructor it finds the value but does not find it otherwise:
public PController(#Value("${allowedVendors}") String allowedVendors) {
}
I cant use the property further in the code as with the constructor I have created two instances of the bean 1 via the constructor and the other created by spring DI. Any ideas why the value doesnt inject without the constructor
Thanks
You need to put it as a parameter in the constructor:
public zitPrintClient(RestTemplateBuilder restTemplateBuilder,
#Value("${app.service.url}") rootUri) {
this.rootUri = rootUri; // if you are only using this once,
// no need to keep this member variable around
restTemplate = restTemplateBuilder
.rootUri(rootUri)
.build();
}
The constructor gets called first when you are creating the object. The member variable, rootUri, would have it's value injected after the object is created. So, rootUri member variable would be null at the time the constructor is called.
(And, imho, for better readability, your class should start with a capital letter, i.e. ZitPrintClient, but it's your code ...)

Resources