Properties in application.properties not getting loaded in Filter class - spring-boot

I am trying to read the value from application.properties in one of the util library Filter we write.
My code is as below.
public class AuthorizationFilter extends GenericFilterBean
{
#Value ("${application.identifier}")
private String appId;
...
}
However the value appId is not read from application.properties though it is defined.
The issue occurs only with Filter classes.
Any pointers on how to fix this?

Like #M.Deinum said , If you let spring-boot manage the life cycle of the filter bean, then you will be able use the #Value annotation :
#Component
#Order(1)
public class CustomFilter implements Filter {
#Value ("${application.identifier}")
private String appId;
#Override
public void doFilter
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
LOG.info(
"Starting for req : {}",
req.getRequestURI());
chain.doFilter(request, response);
LOG.info(
"Anything");
}
// other methods
}
Keep in mind that if you provide your filter this way , you won't have to register it manually and if you want it to work for a particular url by registering it manually remember to remove the #Component annotation so that spring-boot won't take it up automatically.

Let the spring manage your filter class. You can register in your filter class like below :
#Bean
public FilterRegistrationBean registerFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(this);
registration.addUrlPatterns("/*");
return registration;
}

Related

Apache camel dynamic routing

I have following Apache camel rest service(/sales) that internally calls another rest service(/getOrders) and get list of objects. Am able to print JSON response in the processor but getting java objects in response while trying from postman. Could anyone pls help me to resolve the issue. Attaching the response log for ref..
#Component
public class ApplicationResource extends RouteBuilder {
#Autowired
private OrderService service;
#BeanInject
private OrderProcessor processor;
#Override
public void configure() throws Exception {
restConfiguration().component("servlet").port(9090).host("localhost");
rest().get("/getOrders").produces(MediaType.APPLICATION_JSON_VALUE).route().setBody(() -> service.getOrders());
rest().get("/sales").produces(MediaType.APPLICATION_JSON_VALUE).route()
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.toD("http://localhost:9090/getOrders?bridgeEndpoint=true").convertBodyTo(String.class).marshal()
.json(JsonLibrary.Jackson, Order.class).to("log:foo?showHeaders=true");;
;
}
}
You should remove the last .endRest() on "direct:bye" route.
I think you get the rest response before calling your Processor.
This works for me.
First, I needed to set the bindingMode as RestBindingMode.json in the restConfiguration.
Secondly, instead of marshal(), you need to use unmarshal().
Third, since you are returning a list of orders, .json(JsonLibrary.Jackson, Order.class) will not be sufficient to unmarshal the list of orders. You need to use a custom format which will be able to unmarshal the list of orders into a json array. This you need to do using JacksonDataFormat format = new ListJacksonDataFormat(Order.class);
#Override
public void configure() {
JacksonDataFormat format = new ListJacksonDataFormat(Order.class);
restConfiguration().component("servlet").port(9090).host(localhost).bindingMode(RestBindingMode.json);
rest()
.get("/getOrders")
.produces(MediaType.APPLICATION_JSON_VALUE)
.route()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getMessage().setBody(service.getOrders());
}})
.to("log:getOrders?showHeaders=true&showBody=true");
rest()
.get("/sales")
.produces(MediaType.APPLICATION_JSON_VALUE)
.route()
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.toD("http://localhost:9090/getOrders?bridgeEndpoint=true")
.unmarshal(format)
.to("log:sales?showHeaders=true&showBody=true");
}
Solvedddd !!! i did two things as follows,May be use full for some one
1,bindingMode(RestBindingMode.auto) - RestBindingMode changes to auto
from json
2, Added this in the main
service(/getOrders).marshal().json(JsonLibrary.Jackson);
#Component
public class ApplicationResource extends RouteBuilder {
#Autowired
private OrderService service;
#BeanInject
private OrderProcessor processor;
#Override
public void configure() throws Exception {
restConfiguration().component("servlet").port(9090).host("localhost").bindingMode(RestBindingMode.auto);
rest().get("/getOrders").produces(MediaType.APPLICATION_JSON_VALUE).route().setBody(() -> service.getOrders())
.marshal().json(JsonLibrary.Jackson);
rest().get("/sales").produces(MediaType.APPLICATION_JSON_VALUE).route()
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.toD("http://localhost:9090/getOrders?bridgeEndpoint=true").convertBodyTo(String.class)
.log("body = ${body}");
;
;
}
}

Controller interceptor that process endpoint annotation in WebFlux

My team is in the middle of migrating our Spring MVC extensions to WebFlux.
We've got a feature that lets our clients customize metric of controller method. To do that we've created our annotation that is processed by HandlerInterceptorAdapter.
The problem is that I can't see any equivalent of this in Spring WebFlux. I can't use WebFilter because Spring does not know yet which endpoint will be called. How can I implement that?
The closest workaround I found is to use RequestMappingHandlerMapping and somehow build a map of Map<String(path), HandlerMethod>, but this is cumbersome and error prone in my opinion.
Is there any better way to solve this?
Edit:
It goes like this
public class MeteredHandlerInterceptor extends HandlerInterceptorAdapter {
public MeteredHandlerInterceptor() {
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// I save start time of method
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// I read endpoint method from the HandlerMethod, I apply any customisation by our custom #MeteredEndpoint annotation (for example custom name) and I save it in MeterRegistry
}
}
I haven't coded workaround yet because I didn't want to invest time in it, but I see that I could obtain HandlerMethod for path, but I'm not sure I will receive same HandlerMethod as I normally would when the controller is called.
Maybe little bit late, but it can still be useful for someone...
I have not found an easy way to do that, the best I was able to create is a HandlerAdapter bean that intercepts handling in the following way:
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public HandlerAdapter handlerAdapter(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
return new HandlerAdapter() {
#Override
public boolean supports(Object handler) {
return handler instanceof HandlerMethod;
}
#Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
// your stuff here...
// e.g. ((HandlerMethod) handler).getMethod().getAnnotations()...
return requestMappingHandlerAdapter.handle(exchange, handler);
}
};
}
The idea is that this adapter is used for all HandlerMethod handlers (those are the ones created by collecting annotated methods from #Controllers) and delegates the handling to the RequestMappingHandlerAdapter (that would be used directly for HandlerMethod handlers in normal case, notice the #Order annotation here).
The point is you can put your code before/after the invocation of the handle method and you are aware of the method being invoked at this point.
Solution:
#Component
class AuditWebFilter(
private val requestMapping: RequestMappingHandlerMapping
): WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
// if not to call - then exchange.attributes will be empty
// so little early initialize exchange.attributes by calling next line
requestMapping.getHandler(exchange)
val handlerFunction = exchange.attributes.get(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE) as HandlerMethod
val annotationMethod = handlerFunction.method.getAnnotation(MyAnnotation::class.java)
// annotationMethod proccesing here
}
}

#ConfigurationProperties object returned null in spring boot application

I have a config object which is mapped to the config file as below:
#Data
#Component
#ConfigurationProperties("app.cors")
public class DomainProperties {
private Map<String, String> domainMap;
}
and my application.properties config file looks like:
app.cors.domainMap.local=localhost:8080
app.cors.domainMap.onlive=test.com
I am trying to read the values in the domainMap from the above properties file, to set them as Access-Control-Allow-Origin headers for the response of my application. What I did so far is:
public class HeaderInterceptor extends HandlerInterceptorAdapter {
#Autowired
private DomainProperties domainProperties;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
List<String> domainList= domainProperties.getDomainMap().values().stream().collect(Collectors.toList());
domainList.stream().forEach(domain -> response.addHeader("Access-Control-Allow-Origin", domain));
return super.preHandle(request, response, handler);
}
but the problem is I received back a null domainProperties object, therefore a NullPointerException is thrown here.
Can anyone explain me why did I get a null domainProperties object here? and how to resolve this problem. Thank you in advanced!

initParams are not working in WebFilter annotation

I created a filter using following annotations in a java web project created by spring-boot:
#Order(2)
#Component
#WebFilter(
filterName = "jwtFitler",
urlPatterns = "/*",
initParams = { #WebInitParam(name = "excludedPaths", value = "login, hello") }
)
However, the initParams are not working, excludedPaths and excludedUrls are always null. Could anyone help tell me why?
public class MyFilter implements Filter {
private String[] excludedUrls;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
String excludedPaths = filterConfig.getInitParameter("excludedPaths");
System.out.println("excludedPaths:" + excludedPaths);
if(!StringUtils.isEmpty(excludedPaths))
excludedUrls = excludedPaths.split(",");
System.out.println("excludedUrls:" + excludedUrls);
}
//......
}
Due to your use of #Component, your Filter is being found as a plain Spring component. As a result, the #WebFilter configuration has no effect.
If you want Spring Boot to scan for Servlet components (#WebFilter, #WebListener and #WebServlet) you need to use #ServletComponentScan. Typically, that annotation is added to your main application class alongside #SpringBootApplication. With that in place, you should remove #Component from your Filter.

Add more field into header using interceptor of spring boot not work

I'm using spring boot.
I want to add a field into header of every response. So that, i using interceptor. The code is:
#Component
public class ApiVersionInterceptor extends HandlerInterceptorAdapter{
private final Logger log = LoggerFactory.getLogger(ApiVersionInterceptor.class);
#Autowired
private Environment environment;
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception arg3) throws Exception {
String apiVersion = environment.getProperty(ApiVersion.VERSION_KEY.getKey());
log.debug("api-version:"+apiVersion);
response.addHeader("Api-Version", apiVersion);
}
}
And the configuration is:
#Configuration
public class InterceptorsConfiguration extends WebMvcConfigurerAdapter {
#Autowired
private ApiVersionInterceptor apiVersionInterceptor;
/**
* Add interceptor
*/
#Override
public void addInterceptors(final InterceptorRegistry registry) {
//Add api-version field to header of response
registry.addInterceptor(apiVersionInterceptor);
}
}
To make sure this snipped code is run because of:
2017-12-06 02:35:10,392 DEBUG [] [http-nio-8080-exec-7] ApiVersionInterceptor: api-version:1.9.0
But i don't understand, i don't see this field in the header of any response.
Update
My app use Restful webservice, so don't have view phase.
Thanks for help.
You should add header in a earlier phase, override the preHandle method in your ApiVersionInterceptor. Because in afterCompletion response is already committed and skip header changes.

Resources