Can I make a filter initialize after the servlet? - servlet-filters

I have a web application using spring, in which I have a servlet that locads the context in its init method:
private ContextLoader contextLoader;
public void init() throws ServletException {
contextLoader = new ContextLoader();
contextLoader.initWebApplicationContext(getServletContext());
}
In addition, I have a servlet in which I do the following:
public void init(FilterConfig config) throws ServletException {
WebApplicationContext context =
WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
//here I'm using the context
}
The problem: the filter's init() method is called before the servlet initializes, so the context I get in the filter is null. In the web.xml my servlet is configured with load-on-startup=1.
Is there any way I can make my filter initialize after the servlet initializes so that I'll be able to use the WebApplicationContext in the filter?
Thanks!

Try this:
Don't configure the filter in the web.xml
In your servlet, get the ServletContext.
Call ServletContext.addFilter() to add your filter.

Related

Call another rest api from my server in Spring-Boot

I want to call another web-api from my backend on a specific request of user. For example, I want to call Google FCM send message api to send a message to a specific user on an event.
Does Retrofit have any method to achieve this? If not, how I can do that?
This website has some nice examples for using spring's RestTemplate.
Here is a code example of how it can work to get a simple object:
private static void getEmployees()
{
final String uri = "http://localhost:8080/springrestexample/employees.xml";
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);
System.out.println(result);
}
Modern Spring 5+ answer using WebClient instead of RestTemplate.
Configure WebClient for a specific web-service or resource as a bean (additional properties can be configured).
#Bean
public WebClient localApiClient() {
return WebClient.create("http://localhost:8080/api/v3");
}
Inject and use the bean from your service(s).
#Service
public class UserService {
private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(3);
private final WebClient localApiClient;
#Autowired
public UserService(WebClient localApiClient) {
this.localApiClient = localApiClient;
}
public User getUser(long id) {
return localApiClient
.get()
.uri("/users/" + id)
.retrieve()
.bodyToMono(User.class)
.block(REQUEST_TIMEOUT);
}
}
Instead of String you are trying to get custom POJO object details as output by calling another API/URI, try the this solution. I hope it will be clear and helpful for how to use RestTemplate also,
In Spring Boot, first we need to create Bean for RestTemplate under the #Configuration annotated class. You can even write a separate class and annotate with #Configuration like below.
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
Then, you have to define RestTemplate with #Autowired or #Injected under your service/Controller, whereever you are trying to use RestTemplate. Use the below code,
#Autowired
private RestTemplate restTemplate;
Now, will see the part of how to call another api from my application using above created RestTemplate. For this we can use multiple methods like execute(), getForEntity(), getForObject() and etc. Here I am placing the code with example of execute(). I have even tried other two, I faced problem of converting returned LinkedHashMap into expected POJO object. The below, execute() method solved my problem.
ResponseEntity<List<POJO>> responseEntity = restTemplate.exchange(
URL,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<POJO>>() {
});
List<POJO> pojoObjList = responseEntity.getBody();
Happy Coding :)
Create Bean for Rest Template to auto wiring the Rest Template object.
#SpringBootApplication
public class ChatAppApplication {
#Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(ChatAppApplication.class, args);
}
}
Consume the GET/POST API by using RestTemplate - exchange() method. Below is for the post api which is defined in the controller.
#RequestMapping(value = "/postdata",method = RequestMethod.POST)
public String PostData(){
return "{\n" +
" \"value\":\"4\",\n" +
" \"name\":\"David\"\n" +
"}";
}
#RequestMapping(value = "/post")
public String getPostResponse(){
HttpHeaders headers=new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity=new HttpEntity<String>(headers);
return restTemplate.exchange("http://localhost:8080/postdata",HttpMethod.POST,entity,String.class).getBody();
}
Refer this tutorial[1]
[1] https://www.tutorialspoint.com/spring_boot/spring_boot_rest_template.htm
As has been mentioned in the various answers here, WebClient is now the recommended route.
You can start by configuring a WebClient builder:
#Bean
public WebClient.Builder getWebClientBuilder(){
return WebClient.builder();
}
Then inject the bean and you can consume an API as follows:
#Autowired
private WebClient.Builder webClientBuilder;
Product product = webClientBuilder.build()
.get()
.uri("http://localhost:8080/api/products")
.retrieve()
.bodyToMono(Product.class)
.block();
Does Retrofit have any method to achieve this? If not, how I can do that?
YES
Retrofit is type-safe REST client for Android and Java. Retrofit turns your HTTP API into a Java interface.
For more information refer the following link
https://howtodoinjava.com/retrofit2/retrofit2-beginner-tutorial
In this case need download whit my API, files hosted in other server.
In my case, don't need use a HTTP client to download the file in a external URL, I combined several answers and methods worked in previous code for files that were in my local server.
My code is:
#GetMapping(value = "/download/file/pdf/", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<Resource> downloadFilePdf() throws IOException {
String url = "http://www.orimi.com/pdf-test.pdf";
RestTemplate restTemplate = new RestTemplate();
byte[] byteContent = restTemplate.getForObject(url, String.class).getBytes(StandardCharsets.ISO_8859_1);
InputStream resourceInputStream = new ByteArrayInputStream(byteContent);
return ResponseEntity.ok()
.header("Content-disposition", "attachment; filename=" + "pdf-with-my-API_pdf-test.pdf")
.contentType(MediaType.parseMediaType("application/pdf;"))
.contentLength(byteContent.length)
.body(new InputStreamResource(resourceInputStream));
}
and it works with HTTP and HTTPS urls!
Since the question explicitly tags spring-boot, it worth noting that recent versions already ship a pre-configured instance of a builder for WebClient, thus you can directly inject it inside your service constructor without the needing to define a custom bean.
#Service
public class ClientService {
private final WebClient webClient;
public ClientService(WebClient.Builder webClientBuilder) {
webClient = webClientBuilder
.baseUrl("https://your.api.com")
}
//Add all the API call methods you need leveraging webClient instance
}
https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/boot-features-webclient.html
Simplest way I have found is to:
Create an annotated interface (or have it generated from somehing like OpenAPI)
Give that interface to Spring RestTemplate Client
The Spring RestTemplate Client will parse the annotations on the interface and give you a type safe client, a proxy-instance. Any invocation on the methods will be seamlessly translated to rest-calls.
final MyApiInterface myClient = SpringRestTemplateClientBuilder
.create(MyApiInterface.class)
.setUrl(this.getMockUrl())
.setRestTemplate(restTemplate) // Optional
.setHeader("header-name", "the value") // Optional
.setHeaders(HttpHeaders) // Optional
.build();
And a rest call is made by inoking methods, like:
final ResponseEntity<MyDTO> response = myClient.getMyDto();

how to access endpoint configuration in a custom NServiceBus profile handler

I'm migrating code from NSBv4 to NSBv5 (5.2.12 to be exact) and I have a custom profile implementation:
public class MyProfileHandler : IHandleProfile<PerformanceCounters>
{
public MyProfileHandler()
{
}
public void ProfileActivated(BusConfiguration config)
{
// I need to do something based on endpoint configuration, e.g. endpoint name
// this used to work in NSBv4:
// var endpointName = Configure.EndpointName;
}
}
How can I access endpoint configuration here?
I'm hosting this app using NServiceBus.Host (v6.0.0 if it matters) and this is where the IHandleProfile<T> interface comes from.
BusConfiguration is a configuration builder and it seems it's not possible to read anything useful from it. I tried to inject an instance of Configure to the constructor of my profile handler, but then it crashes - NSB needs the handler to have a parameterless constructor.
Implementing IWantTheEndpointConfig is not an option as well, as it is deprecated in v5 and it causes a compilation error. Its obsolete error message states:
IHandleProfile is now passed an instance of Configure
(which would be perfect for my case), but this is not true as far as I can tell (there is no Configure passed to ProfileActivated() and I can't see how I can inject it).
Is my only option to reimplement the profile handler using a completely different approach, or am I missing something?
NServiceBus.Core has an issue how it sets the endpoint name (and unfortunately also the endpoint version) on the BusConfiguration. The set endpoint name is added to the settings dictionary too late. You can work around that issue by doing the following:
public class EndpointConfig : IConfigureThisEndpoint
{
public void Customize(BusConfiguration configuration)
{
var customConfig = new EndpointConfiguration
{
EndpointName = "YourEndpointName",
};
configuration.EndpointName(customConfig.EndpointName);
configuration.GetSettings().Set<EndpointConfiguration>(customConfig);
}
}
public class EndpointConfiguration
{
public string EndpointName { get; set; }
}
BusConfiguration is essentially a dictionary on steroids. If you want to get access to what has been set in the BusConfiguration in the profile handler you can do the following (i.ex. get the endpoint name):
public class MyProfileHandler : IHandleProfile<PerformanceCounters>
{
public void ProfileActivated(BusConfiguration config)
{
var customConfig = config.GetSettings().Get<EndpointConfiguration>();
var endpointName = customConfig.EndpointName;
}
}
In the normal NServiceBus Host the interface offers only the one parameter, BusConfiguration. On Azure the interface offers two methods, where one actually has the Configure object.

jaxrs queryparam not loaded for interceptor

I have a REST service of the form:
#GET
#NeedsInterception
public void getSomething(#QueryParam("xxx") #MyAnnotation String thing) {
//Stuff
}
I then have an interceptor for #NeedsInterception.
In it, I perform some logic on the element annotated with #MyAnnotation.
However, when the interceptor is called, the MethodInvocation object has not yet been resolved with the value of the QueryParam, instead it is always "";
Is there a way for me to make the interception happen after the QueryParam is resolved?
Don't know which kind of interceptor you are using but a jax-rs ReaderInterceptor is intended to wrap calls to MessageBodyReader.readFrom. As you don't send a request body with a #GET request this kind of interceptor won't be used.
A ContainerRequestFilter should help:
#Provider
public class SomeFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
MultivaluedMap<String,String> queryParameters = requestContext.getUriInfo().getQueryParameters();
}
}

How to get target method of a given JAX-RS request?

Is there a way to obtain the java.lang.reflect.Method of the method (which is annotated with #Path) which will be called for a given HttpServletRequest?
Here is my use case : I'm in a Java EE Filter and want to know if the method which will be invoked later is annotated with another specific annotations.
(I'm using RESTEasy 3.0.7)
It's easy if you can use a ContainerRequestFilter instead of a normal Servlet Filter.
#Provider
public class SomeFilter implements ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
Method method = resourceInfo.getResourceMethod();
}
}

Adding global error handling to WCF REST service

I have a WCF/REST Web Service that I'm trying to add a global exception handler to. I'm looking for something similar to the Application_Error event in a standard .NET website.
I've found lots of info about using IErrorHandler and IServiceBehavior like what's detailed here: http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx#Y1479
That seems like what I need, but every example I've found assumes that the service is defined in the web.config. I'm not doing that - I'm using RouteTables, configured in the global.asax, like so:
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
// Edit the base address of Service1 by replacing the "Service1" string below
RouteTable.Routes.Add(new ServiceRoute("", new WebServiceHost2Factory(), typeof(myService)));
}
So, given that, how do I configure my custom IErrorHandler and IServiceBehavior? Am I even on the right track, given that I'm using a RouteTable rather than configuring it via the web.config? I'm very new to WCF....
The wiring up of your IServiceBehaviour can be achieved by creating a custom WebServiceHostFactory that overrides CreateServiceHost.
For example if you have a class GlobalErrorHandlerBehaviour which implements IServiceBehavior, then you could wire it up as follows:
public class CustomWebServiceHostFactory : WebServiceHostFactory
{
protected override ServiceHost CreateServiceHost(System.Type serviceType, System.Uri[] baseAddresses)
{
return ApplyGlobalErrorHandler(base.CreateServiceHost(serviceType, baseAddresses));
}
private ServiceHost ApplyGlobalErrorHandler(ServiceHost serviceHost)
{
serviceHost.Description.Behaviors.Add(new GlobalErrorHandlerBehaviour());
return serviceHost;
}
}
You would then update your call to the ServiceRoute constructor to pass in this custom factory.