Goal
I want to add an object SpecialHeaderBuilder to Spring methods (added using HandlerMethodArgumentResolver), which is then used by a HandlerInterceptor to actually add headers to the response in a very specific way.
Code created
I added the following class to my resolvers, so that I can now use SpecialHeaderBuilder instances in my methods.
public class SpecialHeaderBuilderArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(SpecialHeaderBuilder.class);
}
#Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
return new SpecialHeaderBuilder();
}
}
It is used as follows:
#RequestMapping("...")
public String someMethod(SpecialHeaderBuilder builder) {
// Do something with the builder
return "index"
}
Problem
Now I want to use that builder instance to actually set headers, so I created a HandlerInterceptor:
public class SpecialHeaderBuilderHandlerInterceptor implements HandlerInterceptor {
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// How do I get the instance of the SpecialHeaderBuilder here?
}
}
I am not sure how to actually get the instance. I know I have the method signature, so I can see that the SpecialHeaderBuilder is actually part of the signature. I don't know how to access the builder argument that is modified inside the method. Does anybody know?
XY problem
I can actually change my response object to something like ResponseWithSpecialHeaders and use a HandlerInterceptor for that. However, I am curious if what I thought of as a solution could actually work. I would expect that it is possible, since the Model object works the same way. But maybe that is a special case.
Related
I've got a Spring Boot Controller that returns a List<Person> and I would like to implement a custom HttpMessageConverter that can write collections of type Person.
I see AbstractHttpMessageConverter, but the supports() method only takes a Class, so I can test for Collection, but no way (as far as I know) to test for a Collection of type Person.
I also see GenericHttpMessageConverter and AbstractGenericHttpMessageConverter which sound promising, but I can't figure out to properly implement one.
I think I found a solution. The following seems to work...
#Component
static class PersonMessageConverter
extends AbstractGenericHttpMessageConverter<Collection<Person>> {
public PersonMessageConverter() {
super(MediaType.APPLICATION_JSON);
}
#Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
TypeToken<Collection<Person>> personCollectionType = new com.google.common.reflect.TypeToken<>() {};
return canWrite(mediaType) && personCollectionType.isSupertypeOf(type);
}
#Override
protected void writeInternal(Collection<Person> persons, Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
// do write...
}
// continue with read methods here
}
New to Spring Boot here. Spring MVC provides the #SubdomainMapping annotation, which does not seem to be available from what I can see in Spring Boot. I've seen a few people discuss using a filter to handle this. Or other approaches that seem overly convoluted.
Would there not be a (simple/cleaner) way to handle all sub-domains within a standard controller such as:
#SubdomainMapping(value = {"**"}
public String data(ModelMap modelMap, HttpServletRequest request) {
//Code to handles subdomain logic here ....
}
This would be a simple approach where all values are treated equally with minor differences.
Any suggestions would be helpful!
I have worked on this myself and I have an answer that isn't as simple as you wanted, but I don't think there is one that simple.
So, you can create a handler interceptor adapter that will grab every request before it gets to your controller and grabs and processes the subdomain. This would require something like this:
#Component
public class SubDomainInterceptor extends HandlerInterceptorAdapter {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception arg3)
throws Exception {
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView model)
throws Exception {
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
String mysub = request.getRequestURL().toString();
//...
// Do whatever you need to do with the subdomain
//
if (isGoodSubdomain){
session.sendAttribute("subdomain", mysub);
} else {
response.sendRedirect("http://www.basesite.com"):
}
return true;
}
You then use that session variable in your controllers to filter values or whatever you need to use them for. I know this isn't the simple answer you wanted, but it was the best one that I have found so far.
After a long time debugging my app, I realized something which makes no sense to me. Whenever I call a controller annotated as exemplified below, my Interceptor is executed twice.
#RequestMapping(method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public ResponseEntity<byte[]> getMedia(String url) throws IOException {
...
}
For testing purposes I removed the "produces" part and the same interceptor is only called once.
Can someone please enlighten me why is this happening? The fact it is being called twice is generating errors, because on the second call all request headers are empty and thus my validations fail.
My interceptor is simply an implementation as follow:
public class AuthenticatorInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//validations
return super.preHandle(request, response, handler);
}
Check if your class also has a #RequestMapping annotation producing a different mimetype. Maybe this is the source of your problem, since both "produces" declaration might be the reason your interceptor is being called twice.
I am new to java reflection.I will directly come to the question.
This is my class
public class RequestClass{
#XmlElement(name="Request")
private Request mRequest;
public Request getRequest() {
return mRequest;
}
public void setRequest(Request request) {
this.mRequest= request;
}
this my another class in this I am passing RequestClass object here
//The supplied requestObject is of type RequestClass
Object initialize(Object requestObject) {
//requestObject
}
In this code I want to manipulate, dynamically, the request property of the RequestClass. I don't know how to proceed further, so if anyone could provide some guidance, I would appreciate it. Thanks.
try this requestObject.getClass().getMethod(method_name).invoke(requestObject);
also, there is an overload of getMethod & invoke, through which you can pass parameter to that method (like in setters)
Currently I have a class, TransactionData, which is just a little bit more than a POJO. I build the object from an HTTPServletRequest. What I do:
public class TransactionData
{
// ...
public TransactionData(HttpServletRequest request) throws IOException
{
// do actual work here
}
}
There many WTF here, the most disturbing one is that the object TransactionData is tightly coupled to HTTPServletRequest. What I thought: create an interface, TransactionDataExtractor, with an extract() method, so that I might implement different classes to build the object.
public interface TransactionDataExtractor
{
public TransactionData extract();
}
But how do I pass the stuff needed to build the TransactionData to every implementation? The firt thing that came to mind was to use the different constructors, like this:
public class TransactionDataExtractorRequest implements TransactionDataExtractor
{
private HttpServletRequest httpRequest;
public TransactionDataExtractorRequest(HttpServletRequest httpRequest)
{
this.httpRequest = httpRequest;
}
public TransactionData extract()
{
// do whatever is required
}
}
But in this case whenever I need to build a new TransactionData object I have to create a new TransactionDataExtractorRequest. An implicit dependency I don't like at all.
The other alternative I could think of was passing an Object parameter to extract() and cast it whenever required, giving up the type safety and introducing a lot of boiler plate ugly code
public TransactionData extract(Object o)
{
HttpServletRequest h;
if (o instanceof HttpServletRequest)
{
h = (HttpServletRequest)o;
}
//...
}
I don't know if I have made myself clear. I do feel like I'm missing something, I know the solution is very simple but I can't get hold of it.
Any thoughts?
TIA.
EDIT: the problem might even be that my hunch is completely wrong and I may dismiss it without any regret
If your only problem is ensuring type safety when passing the source object to extract(), you can use generics:
public interface TransactionDataExtractor<E> {
public TransactionData extract(E source);
}
public class TransactionDataExtractorRequest
implements TransactionDataExtractor<HttpServletRequest> {
public TransactionData extract(HttpServletRequest source) { ... }
}
I do feel like I'm missing something ... Any thoughts?
Well my thought is that you are attempting to solve a problem that isn't really a problem. There's no obvious (to me) reason why the coupling you are trying to get rid of is actually harmful. Certainly, your attempts to remove the coupling are not making the code any easier to understand.
In case you rely on request parameters only, you can get request.getParameterMap() and use the Map instead. (if you need headers - getHeaders())
Creating/reusing a TransactionDataExtractorRequest instance isn't a problem, IMHO. You'd need to somewhere distinguish between the parameter types anyway and if you decouple TransactionData and the parameter types by using some sort of factory, what's wrong with that?
I'm still not convinced that much is gained by removing the dependency on HttpServletRequest, but I would suggest something along the lines of:
public class TransactionData {
public TransactionData(TransactionDataOptions options) throws IOException {
// do actual work here
}
}
//TransactionData wants some state that it currently gets from a HttpServletRequest,
//figure out what that state is, and abstract an interface for accessing it
public interface TransactionDataOptions {
//getters for things that TransactionData needs
}
//take all the code that pulls state out of the HttpServletRequest, and move it here
public class TransactionDataHttpOptions implements TransactionDataOptions {
private HttpServletRequest request;
//getter implementations that pull the required information out of the request
public TransactionDataHttpOptions(HttpServletRequest request) {
this.request = request;
}
}
//now you can also do this, and use TransactionData even without a HttpServletRequest
public class TransactionDataMapOptions implements TransactionDataOptions {
private Map<String, Object> map;
//getter implementations that pull the required information out of the map
public TransactionDataHttpOptions(Map<String, Object> map) {
this.map = map;
}
}
If you go this route, then TransactionDataHttpOptions is the only object with a dependency on HttpServletRequest. And since it is basically a wrapper that is intended to work with a HttpServletRequest I think that should be fine.