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

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.

Related

Quarkus extension - How to have an interceptor working on beans provided by the extension itself

I'm working on a Quarkus extension that provides an interceptor (and its annotation) to add some retry logic around business methods this extension offers. Nothing new in there, and this is working when i annotate a public method of a bean in an application that uses this extension.
But the extension also provides some #ApplicationScoped beans that are also annotated, but the interceptor is not intercepting any of these.
Seems like an interceptor does not check / apply on the extension itself.
I would like to know if this is an intended behavior, or an issue in my extension setup, and if so how to fix it. Could not find anything about this in the documentation, but there is so much dos that i may have missed something.
Any idea about this ?
I finally found a way to make this work.
I was using a producer bean pattern to produce my beam as an #ApplicationScoped bean inside the extension.
#ApplicationScoped
public class ProxyProducer {
#Produces
#ApplicationScoped
public BeanA setUpBean(ExtensionConfig config)
{
return new BeamsClientProxy(new InternalBean(config.prop1, config.prop2));
}
}
with the following BeanA class (just an example)
public class BeanA {
private final InternalBean innerBean;
public BeanA(final InternalBean innerBean) {
this.innerBean = innerBean;
}
#MyInterceptedAnnotation
public void doSomething() {
}
}
Due to this setup, the bean is not considered by the interceptor (i guess because it's produced only the first time it's used / injected somewhere else)
Removing the producer pattern and annotating directly the BeanA fixed the issue.
Example:
#ApplicationScoped
public class BeanA {
private final InternalBean innerBean;
public BeanA(final ExtensionConfig config) {
this.innerBean = new InternalBean(config.prop1, config.prop2);
}
#MyInterceptedAnnotation
public void doSomething() {
}
}
with of course adding the following lines to register the bean directly on the extension processor:
#BuildStep
AdditionalBeanBuildItem proxyProducer() {
return AdditionalBeanBuildItem.unremovableOf(BeanA.class);
}
As a conclusion:
Changing the bean implementation to avoid the producer-based bean use case solved my issue (please refers to Ladicek comment below)
Edit:
As Ladicek explained, Quarkus doesn't support interception on producer-based beans.

#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.

Hystrix Javanica : Call always returning result from fallback method.(java web app without spring)

I am trying to integrate Hystrix javanica into my existing java EJB web application and facing 2 issues with running it.
When I try to invoke following service it always returns response from fallback method and I see that the Throwable object in fallback method has "com.netflix.hystrix.exception.HystrixTimeoutException" exception.
Each time this service is triggered, HystrixCommad and fallback methods are called multiple times around 50 times.
Can anyone suggest me with any inputs? Am I missing any configuration?
I am including following libraries in my project.
project libraries
I have setup my aspect file as follows:
<aspectj>
<weaver options="-verbose -showWeaveInfo"></weaver>
<aspects>
<aspect name="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"/>
</aspects>
</aspectj>
Here is my config.properties file in META-INF/config.properties
hystrix.command.default.execution.timeout.enabled=false
Here is my rest service file
#Path("/hystrix")
public class HystrixService {
#GET
#Path("clusterName")
#Produces({ MediaType.APPLICATION_JSON })
public Response getClusterName(#QueryParam("id") int id) {
ClusterCmdBean clusterCmdBean = new ClusterCmdBean();
String result = clusterCmdBean.getClusterNameForId(id);
return Response.ok(result).build();
}
}
Here is my bean class
public class ClusterCmdBean {
#HystrixCommand(groupKey = "ClusterCmdBeanGroup", commandKey = "getClusterNameForId", fallbackMethod = "defaultClusterName")
public String getClusterNameForId(int id) {
if (id > 0) {
return "cluster"+id;
} else {
throw new RuntimeException("command failed");
}
}
public String defaultClusterName(int id, Throwable e) {
return "No cluster - returned from fallback:" + e.getMessage();
}
}
Thanks for the help.
If you want to ensure you are setting the property, you can do that explicitly in the circuit annotation itself:
#HystrixCommand(commandProperties = {
#HystrixProperty(name = "execution.timeout.enabled", value = "false")
})
I would only recommend this for debugging purposes though.
Something that jumps out to me is that Javanica uses AspectJ AOP, which I have never seen work with new MyBean() before. I've always have to use #Autowired with Spring or similar to allow proxying. This could well just be something that is new to me though.
If you set a breakpoint inside the getClusterNameForId can you see in the stack trace that its being called via reflection (which it should be AFAIK)?
Note you can remove commandKey as this will default to the method name. Personally I would also remove groupKey and let it default to the class name.

Class xxx does not contain a public constructor needed to autobuild when xxx become a Tapestry Service

I'm discovering the wonderful integration work made by Tynamo's team between Tapestry and Resteasy .
I'm trying to activate Liveclass Reloading on webservices. As per doc says :
Documentation
The only thing you need to do to enable live class reloading for your
REST services is to bind them as regular Tapestry IoC services and
contribute them to javax.ws.rs.core.Application.class. Read more about
how service implementation reloading works in:
http://tapestry.apache.org/reload.html
Here is an example from the tapestry-resteasy test suite.
public static void bind(ServiceBinder binder)
{
binder.bind(ReloadableEchoResource.class, ReloadableEchoResourceImpl.class);
}
#Contribute(javax.ws.rs.core.Application.class)
public static void configureRestResources(Configuration<Object> singletons, ReloadableEchoResource reloadableEchoResource)
{
singletons.add(reloadableEchoResource);
}
My Own Work
This is exactly what I'm doing (well ... hmmm at least I believe that it is ;D):
My binding
public static void bind(ServiceBinder binder)
{
binder.bind(PushMessageService.class, GCMPushMessageServiceImpl.class);
binder.bind(UserService.class, HibernateUserServiceImpl.class);
binder.bind(IUserResource.class, UserResourceImpl.class);
}
/**
* Contributions to the RESTeasy main Application, insert all your RESTeasy singletons services here.
*/
#Contribute(javax.ws.rs.core.Application.class)
public static void configureRestResources(Configuration<Object> singletons, IUserResource userResource)
{
singletons.add(userResource);
}
My Interface
#Path("/user")
public interface IUserResource {
/**
* Lecture de tous les utilisateurs
*
* #return une List des utilisateurs existants
*/
#GET
#Produces("application/json")
public abstract List<User> getAllDomains();
Error
But when I start my app, I obtain this message :
HTTP ERROR 500
Problem accessing /user. Reason:
Exception constructing service 'ResteasyRequestFilter': Error building service proxy for service 'Application' (at org.tynamo.resteasy.Application(Collection) (at Application.java:14) via org.tynamo.resteasy.ResteasyModule.bind(ServiceBinder) (at ResteasyModule.java:31)): Error invoking service contribution method org.tynamo.resteasy.ResteasyModule.javaxWsRsCoreApplication(Configuration, ObjectLocator, ResteasyPackageManager, ClassNameLocator): Class com.sopragroup.ecommerce.mobile.rest.IUserResource does not contain a public constructor needed to autobuild.
Caused by:
java.lang.RuntimeException: Exception constructing service 'ResteasyRequestFilter': Error building service proxy for service 'Application' (at org.tynamo.resteasy.Application(Collection) (at Application.java:14) via org.tynamo.resteasy.ResteasyModule.bind(ServiceBinder) (at ResteasyModule.java:31)): Error invoking service contribution method org.tynamo.resteasy.ResteasyModule.javaxWsRsCoreApplication(Configuration, ObjectLocator, ResteasyPackageManager, ClassNameLocator): Class com.sopragroup.ecommerce.mobile.rest.IUserResource does not contain a public constructor needed to autobuild.
at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.obtainObjectFromCreator(JustInTimeObjectCreator.java:75)
at org.apache.tapestry5.ioc.internal.services.JustInTimeObjectCreator.createObject(JustInTimeObjectCreator.java:54)
It's quite like the autobinding don't works (indeed I do think it is).
Obviously, when I try to without creating an interface and binding, it works like a charm.
Can someone give me a clue ?
I think the issue is that tapestry-resteasy is trying to autobuild IUserResource because it's in the "rest" package.
Here is a very important documentation line that you may have missed:
One more thing: DO NOT put this service in the autodiscovery package.
This is an important line and it was somehow hidden in the docs so I added a warning to make it more visible for future users: http://docs.codehaus.org/pages/diffpagesbyversion.action?pageId=151847035&selectedPageVersions=24&selectedPageVersions=23

Unable to return collections or arrays from JAX-WS Web Service

I found that I was unable to return collections from my JAX-WS Web Service.
I appreciate that the Java Collections API may not be supported by all clients, so I switched to return an array, but I can't seem to do this either.
I've set up my web service as follows:
#WebService
public class MyClass {
public ReturnClass[] getArrayOfStuff() {
// extremely complex business logic... or not
return new ReturnClass[] {new ReturnClass(), new ReturnClass()};
}
}
And the ReturnClass is just a POJO. I created another method that returns a single instance, and that works. It just seems to be a problem when I use collections/arrays.
When I deploy the service, I get the following exception when I use it:
javax.xml.bind.MarshalException - with linked exception:
[javax.xml.bind.JAXBException: [LReturnClass; is not known to this context]
Do I need to annotate the ReturnClass class somehow to make JAX-WS aware of it?
Or have I done something else wrong?
I am unsure of wheter this is the correct way to do it, but in one case where I wanted to return a collection I wrapped the collection inside another class:
#WebService
public class MyClass {
public CollectionOfStuff getArrayOfStuff() {
return new CollectionOfStuff(new ReturnClass(), new ReturnClass());
}
}
And then:
public class CollectionOfStuff {
// Stuff here
private List<ReturnClass> = new ArrayList<ReturnClass>();
public CollectionOfStuff(ReturnClass... args) {
// ...
}
}
Disclaimer: I don't have the actual code in front of me, so I guess my example lacks some annotations or the like, but that's the gist of it.

Resources