How to inject HttpServletRequest into a Spring AOP request (custom scenario)? - spring-aop

I know the standard way of writing an AOP advice around a controller method and that you can get access to the HttpServletRequest arg, if declared in controller method.
But my scenario is that I have a translation service, that is currently session-scoped maintaining the user's locale for translation. I feel this makes the service stateful and also I do not want it to be session-scoped, as I think it is really Singleton. But there are multiple places where the translation service methods are called and so I do not want to change the signature to add request/locale in these methods. The problem is that all the callers of the translation service's methods do not have access to HttpServletRequest (not controller methods)? Can I write an aspect around the translation service methods and somehow magically get access to HttpServletRequest regardless of whether it is available in the caller's context or not?
#Service
public class TranslationService {
public void translate(String key) {
...
}
}
#Aspect
#Component
public class LocaleFinder {
#PointCut("execution(* TranslationService.translate(..))")
private void fetchLocale() {}
#Around("fetchLocale()") // in parameter list
public void advice(JoinPoint joinpoint, HttpServletRequest request) { .... }
}
If now, the caller of translate does not have HttpServletRequest, can't I get request in the advice? Is there a workaround?

Can I write an aspect around the translation service methods and
somehow magically get access to HttpServletRequest regardless of
whether it is available in the caller's context or not?
Not easily. Actually, it would require a lot of effort.
The easy way to do it is to rely on RequestContextHolder. In every request, the DispatcherServlet binds the current HttpServletRequest to a static ThreadLocal object in the RequestContextHolder. You can retrieve it when executing within the same Thread with
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
You can do this in the advice() method and therefore don't need to declare a parameter.

You should be able to auto-wire a HttpServletRequest in your aspect. Spring provides a proxy to the current thread local request instance that way.
So just add:
#Autowired private HttpServletRequest request;
to your aspect. Better yet is to use constructor injection.

Related

#AfterReturning from ExceptionHandler not working

I have a GlobalExceptionHandler class which contain multiple methods annotated with #ExceptionHandler.
#ExceptionHandler({ AccessDeniedException.class })
public final ResponseEntity<Object> handleAccessDeniedException(
Exception ex, WebRequest request) {
return new ResponseEntity<Object>(
"Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
I have a AOP which is suppose to be triggered after the exception handler returns response.
#AfterReturning(value="#annotation(exceptionHandler)",returning="response")
public void afterReturningAdvice(JoinPoint joinPoint, Object response) {
//do something
}
But the #AfterReturning is not triggered after the handler returns a valid response.
Tried full qualified name but not working
#AfterReturning(value = "#annotation(org.springframework.web.bind.annotation.ExceptionHandler)", returning = "response"){
public void afterReturningAdvice(JoinPoint joinPoint, Object response) {
//do something
}
Please go through the documentation to understand the proxying mechanisms in Spring framework.
Assuming the ExceptionHandler code written was of the following format
#ControllerAdvice
public class TestControllerAdvice {
#ExceptionHandler({ AccessDeniedException.class })
final public ResponseEntity<Object> handleAccessDeniedException(
Exception ex, WebRequest request) {
return new ResponseEntity<Object>(
"Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
}
key points from the documentation pertaining to the question are
Spring AOP uses either JDK dynamic proxies or CGLIB to create the
proxy for a given target object.
If the target object to be proxied implements at least one
interface, a JDK dynamic proxy is used. All of the interfaces
implemented by the target type are proxied. If the target object
does not implement any interfaces, a CGLIB proxy is created.
With CGLIB, final methods cannot be advised, as they cannot be overridden in runtime-generated subclasses.
OP identified the issue based on the comments and hints , this answer is for any future references.

Can I share local data between Camel Routes in the same Camel context?

I have a route (route1), which sends data to an HTTP endpoint. To do this, it must set an authorization header.
The header value times out every hour and must be renewed.
For this I have created another route (route2), which gets the access token from a web service at a regular interval using provided credentials (getCredentials). This works fine.
How do I make the access token available to route1?
I have tried simple local variables, static variables, AtomicReference variables (volatile and static...)
My code (shortened for readability):
public class DataRoute extends RouteBuilder{
volatile static AtomicReference<String> cache = new AtomicReference<>();
#Override
public void configure() throws Exception {
from("timer://test?period=3500000")
.routeId("route2")
.setHeader("Authorization", constant(getCredentials()))
.to("http://127.0.0.1:8099/v1/login")
.process(exchange -> {
cache.set(parseAuthString(exchange.getIn().getBody(String.class)));
});
... other route producing for direct:rest
from("direct:rest")
.routeId("route1")
.setHeader("Authorization",constant((cache.get()==null?"":cache.get())))
.to("http://localhost:8099/v1/shipment");
}
}
The cached value is always empty...
Do not use constant to set dynamic values, its a one-time CONSTANT only.
Instead use an inlined processor (you can use java 8 lambda) or message transform / setBody with a processor.

Spring Controller sometimes has null #Autowired objects and seems not to be managed by Spring Context

I have a Spring controller defined like this with 2 request mappings, one using localDAO and the other using dependencyDAO. LocalDAO classes exist in my project and DependencyDAO classes are imported via maven dependency:
#RestController
#PreAuthorize("hasRole('USER')")
public class MyController
#Autowired
private localDAO LocalDAO; // dao classes exist in my project
#Autowired
private DependencyDAO dependencyDAO; // dao classes imported via maven dependency
...
#RequestMapping("/getUsingLocalDAO")
private String getUsingLocalDAO(
#JsonProperty("param") String param) {
localDAO.get(param) ... // <== this never null
}
#RequestMapping("/getUsingDependencyDAO")
private String getUsingDependencyDAO(
#JsonProperty("param") String param) {
dependencyDAO.get(param) ... // <== this always null
}
...
My dao beans are defined in another class:
#Configuration
public class DaoBeans {
#Bean
public LocalDAO localDAO() throws Exception {
return new LocalDAOImpl();
}
#Bean
public DependencyDAO dependencyDAO () throws Exception {
return new DependencyDAOImpl();
}
...
I am doing an $http.post from Angular like this:
$http.post('getUsingLocalDAO', $.param($scope.parameters), {
headers : {
"content-type" : "application/x-www-form-urlencoded"
}
}).success(function(data) {
...
}).error(function(data) {
...
$http.post('getUsingDependencyDAO', $.param($scope.parameters), {
headers : {
"content-type" : "application/x-www-form-urlencoded"
}
}).success(function(data) {
...
}).error(function(data) {
...
Both posts are identical except for the method they execute.
When stepping through the debugger I can see all the dao beans being created.
When I call getUsingLocalDAO everything works as expected.
But, when I call getUsingDependencyDAO every #Autowired object is null.
I believe I am getting different instances of MyController. One managed by Spring and one not; or at least not instantiated properly.
I make these calls in succession. It doesn't matter what order they are in.
I tried injecting the servlet context via #Autowired to get the bean manually but it is always null in getUsingDependencyDAO as well.
I tried using application context aware and although I see the context setter being set in the debugger the context is always null in getUsingDependencyDAO.
If I wrap the two calls in a third request mapping like so everything works well (no null objects).
#RequestMapping("/getUsingBothDAO")
private String getUsingBothDAO(
#JsonProperty("param") String param) {
getLocalDAO(param);
getDependencyDAO(param);
...
}
I am using Spring-Boot 4.1.5. My project is 100% annotation driven and has no .xml configurations. The only difference between the two request mappings is that one uses a bean from a dependency and one does not.
I have been searching for an answer to this problem for 3 days and have not found anything close to what I am experiencing.
Can anyone shed some light as to what I am doing wrong? Any help would be greatly appreciated.
Thanks.
Ok, I solved the problem. My example code above is not entirely accurate. The request method that was giving me nulls was defined as a private method while the one that worked was defined as public as its supposed to be. Originally the private method was not a request method and that modifier remained after the change. I changed it to public and everything is working.
It was just coincidence that the private method was from an imported project. It's curious that Spring did not throw an error that the request mapping didn't exist on the private method or something to that effect.
Thanks to anyone who looked at this and was trying to figure it out.

Asynchronous Begin/End pattern for webservices in silverlight project

I found that the proxy generated with SlSvcUtil.exe (or by adding reference to Web References) only supports Event based async model which is absolutely inappropriate from design point of view (events were 2nd class citizens from the first days).
I'm going to implement F#'s async builder approach and I found "old style" Begin/End are much easier to be generalized. I notices SlSvcUtil.exe generates Begin/End methods pair but marks them both with private keyword?
A couple options on top of my head are:
expose Begin/End methods by updating the proxy class by hand
use wsdl.exe and create wrapper library for missing System.Web classes
use other communication protocols (HttpClient, Tcp)
use third-party proxies (failed to find any so far)
Any ideas?
Say someone created a remote service with one method:
public interface CompressService
{
public byte[] Compress(byte[] inData);
}
After SlSvcUtil I got:
public class CompressServiceSoapClient: ClientBase<CompressServiceSoap...
{
private BeginOperationDelegate onBeginCompressDelegate;
private EndOperationDelegate onEndCompressDelegate;
public event System.EventHandler<CompressCompletedEventArgs> CompressCompleted;
public void CompressAsync(byte[] inData, object userState);
}
While in fact I need:
public class CompressServiceSoapClient: ClientBase<CompressServiceSoap...
{
public IAsyncResult BeginCompress(byte[] inData, System.AsyncCallback callback, object asyncState);
public byte[] EndCompress(IAsyncResult result);
}
Answer
The solution is to declare contract interface with async methods and do not use generated code inherited from ClientBase<>. The article http://msdn.microsoft.com/en-us/library/dd744834(v=vs.95).aspx describes this in more details.
You can access the begin/end methods by using the channel factory for the end point.
Basically just create a new ChannelFactory and pass in a binding and end point. You can use the host source to dynamically update the end point so it's not hard-coded. The resulting instance will expose the begin/end methods for you.

Is possible in WCF service: method return IList<object> when object can be Person class?

Is possible in WCF service: method return IList when object can be Person class?
Ex: in IServiceContract.cs
[ServiceContract]
public interface IDAS
{
[OperationContract]
void DoWork();
[OperationContract]
List<object> GetAnyClass();
}
And class:
public class DAS : IDAS
{
public void DoWork()
{
}
public List<object> GetAnyClass()
{
List<Person> a = new List<Person>();
a.Add(new Person());
return a;
}
}
The problem at runtime is:
System.ServiceModel.CommunicationException: The server did not provide a meaningful reply; this might be caused by a contract mismatch, a premature session shutdown or an internal server error
Theoretically yes, although you need to tell the service that it might be expecting a Person object using the KnownTypeAttribute on your method.
[OperationContract]
[KnownType(typeof(Person))]
List<object> GetAnyClass();
I would really think twice about doing this in practice though - instead declare different method signatures for the objects you're expecting to return:
[OperationContract]
IList<Person> GetPeople();
[OperationContract]
Person GetPerson();
[OperationContract]
IList<Book> GetBooks();
[OperationContract]
Book GetBook();
etc.
It's supposed to be a contract, i.e. concrete, so if you suddenly change the type of class you return it can really mess the clients up.
Also in your example you were returning a concrete List class - this should be avoided, instead use either IList<> or Collection<>.
Yes it is possible, you need to update the reference in Visual Studio (or whatever you are using to generate the proxy class with) and change the collection type returned. There is an option in 'Configure Service Reference' and you can select Generic.List in there (right click your WCF service reference).
The mismatch is because you have changed your service on the server end and not got a new proxy. So change it to return a Generic.List and then regenerate using the steps in 1.
Hope that helps
Ryan
You can return an IList but it's definitly not a good approach to take.
When you expose your services you need people at the other end of the service to know what they are getting.
IList<Person> would be clearer for everybody that use the services or that code in the services.
If you need a method that can return different type of object just split them out in multiple operations.
IList<Person> GetPersons(...)
IList<Animal> GetAnimals(...)
My 2 cents.
Cheva (et al),
There is nothing stopping you from calling a single method to fill in the collection(s) you return from the service calls.
IList<Person> GetPersons(...)
IList<Animal> GetAnimals(...)
Both GetPersons() and GetAnimals() can certainly call an internal method e.g.
IList<Animal> GetAnimals(...)
{
// get list of objects of a given type
internalIList<Object> genericResults = GetItems(
ItemType.Persons|ItemType.Animals );
...
IList<Animal> results;
// convert to specific type
results = new IList<Animal>(genericResults);
return results;
}
That should work, but I didn't test it or anything. YMMV. ; )
-Scott

Resources